Why does `print <$> (print "hello")` print "hello"?

Viewed 649

When calculating IO (IO ()), both (IO ()) and () is calculated, so why

main :: IO (IO ())
main = print <$> (print "Hello, World!")

print

"Hello, World!"

not

IO "Hello, World!" -- ??
"Hello, World!"
1 Answers
main :: IO (IO ())
main = print <$> (print "Hello, World!")

is equivalent, thanks to the monad laws, to

main :: IO (IO ())
main = do 
   result <- print "Hello, World!"
   return (print result)

Now, print always returns () as result, so the whole code is equivalent to

main :: IO (IO ())
main = do 
   _ <- print "Hello, World!"
   return (print ())

Finally, the result of main is simply discarded. That is, the last line could be return (putStrLn "this is ignored") and have the same effect.

Hence the code will only execute the first print "Hello, World!".

I would recommend that you always define main :: IO (). Haskell allows us to declare main :: IO AnyTypeHere, but this is (IMO) confusing.

I would also recommend you use putStrLn, and not print to print strings, since the latter will quote and escape the whole string.

Related