I learned from chapter 9 of Learn You A Haskell For Great Good that
By convention, we don't usually specify a type declaration for
main
.
As far as I can tell, this convention is widespread. However, if I compile, using the -Wall
flag, a program that lacks a type signature for main
, such as
-- test.hs
-- main :: IO ()
main = print (1 :: Int)
GHC does issue a warning:
$ ghc -Wall test.hs
[1 of 1] Compiling Main ( test.hs, test.o )
test.hs:2:1: Warning:
Top-level binding with no type signature: main :: IO ()
Linking test ...
$
I'm confused... If a type signature for main
is indeed superfluous, why would -Wall
cause GHC to complain when it's missing? Are there good reasons (aside from getting rid of that warning) for specifying main
's type anyway?
It's actually a very good idea to write a type signature for
main
, since otherwise if you get too fancy trying to write things in point-free form, you can end up withmain
of typeIO (IO ())
. This is accepted (the language standard saysmain
just has to have some type of the formIO a
) but the "inner IO action" that is the result ofmain
will just be discarded, which is almost certainly not what you wanted (you probably wanted tojoin
it).Well, generally speaking, as that warning makes clear, it's always a good idea to give top-level bindings a type signature. In fact, it would be more reasonable to say
Certainly, in a big project,
main
itself makes up a neglectable effort, so it really doesn't make any sense to omit the signature. Just write it out, for sake of consistency.However, though Haskell is great for properly structured projects and actually there's a tendency to write almost everything in libraries, it's also surprisingly good as a quick scripting language, for stuff other people would write in Python or Perl. And in those cases, you generally don't care that much about safety and good documentation etc., you just want to quickly write down something as concise as possible that does the job. You also normally don't compile those scripts with
-Wall
but just execute them withrunhaskell
. And as scripts always need to contain amain
(unlike most other Haskell source files), it is indeed sensible enough to omit the signature here.I'd still suspect that the majority of Haskellers nowadays do write
main::IO()
even in the simplest scripts, if just out of habit.1Only everything on the top-level, that is. Local signatures sometimes do make sense as well, but often they rather clutter the code.