Haskell - What makes 'main' unique?
With this code:
main :: FilePath -> FilePath -> IO ()
main wrPath rdPath = do x <- readFile rdPath
writeFile wrPath x
I got the following error:
Couldn't match expected type 'IO t0'
with actual type 'FilePath -> FilePath -> IO()
But the file compiles correctly when I change the name of 'main' to something else.
What's so unique about main and why does its type have to be开发者_如何学运维 IO t0
?
Because the language spec says so.
A Haskell program is a collection of modules, one of which, by convention, must be called
Main
and must export the valuemain
. The value of the program is the value of the identifiermain
in moduleMain
, which must be a computation of typeIO t
for some typet
(see Chapter 7). When the program is executed, the computationmain
is performed, and its result (of typet
) is discarded.
As GolezTrol said, all programs need to know which symbol to start executing when the function is invoked. Many scripting languages don't require (or just don't need) a main
routine as they can have statements placed on the top level. This is not the case for Haskell, C and many others - these languages need a starting location and by convention that is the main
function (as per the Haskell spec - see Cat's answer).
Notice Haskell's main
does not accept any parameters that correspond to the program arguments - these are obtained via System.Environment.getArgs
.
As in C, Java, or C#, main
is a special identifier in certain contexts that indicates where the program should start.
In Haskell, main
is defined to have the type IO a
. You should either give your function a different name, or if you really want it to be the starting point, change its signature and have it read the arguments from the command line with getArgs
Although you didn't ask it specifically, main
is also special in that it is the only function in a Haskell program that can (safely) invoke IO actions. The Haskell runtime treats main
as special.
By definition, main
is a function that takes no arguments and returns a value of type IO a
that is discarded by the runtime. What your error message is saying is that your main
does not comply with these requirements. This is indeed true, as your main
receives two parameters.
In order to access command line parameters, use System.Environment.getArgs
.
What's so unique about
Main.main
?
Now that Haskell has an FFI, it's figuratively simple:
This code: | (sort of) | ends up as: |
---|---|---|
module Main(main) where main :: IO () ⋮ |
≈ | module Main() where foreign export "Hmain" main:: IO () ⋮ |
(..."figuratively", not "literally" - making that work is left as an exercise ;-)
So what makes Main.main
unique is that it's visible outside Haskell by default, allowing the runtime system to call your Haskell program. For any other Haskell definition, you would need to use the FFI.
Why does its type have to be
IO t
?
Because in Haskell only values of type IO ...
(usually referred to as actions) can have visible effects e.g. writing to a file. Furthermore, the runtime system can only call Main.main
correctly if it is an IO
action.
I know this question is ancient, but I figured I should mention that you can name anything you want main
in a module that is not (explicitly or implicitly) named Main
. So
module Foo where
main :: Int -> Bool
main = (>3)
will compile just fine. But if you leave out the module header, or use module Main where ...
, then it won't.
精彩评论