fmap putStrLn getLine does not perform IO

不问归期 提交于 2021-02-07 18:28:17

问题


The title said it all, actually. I can't understand why this following code does not actually print "Hello World" as opposed of what >>= does.

main = fmap putStrLn getLine

Currently, here is my line of reasoning, please check if it has any fallacy.

If we compare fmap with >>=

(>>=) :: Monad m => m a -> (a -> m b) -> m b
fmap :: Functor f => (a -> b) -> f a -> f b

In bind, the context, or in IO terms "World" the first m and the second m is entirely different aside of the types. (a -> m b) essentially recreates a new "World". This is not true in Functor, the context f are the same hence side effects are impossible.

Now, if that's indeed the case, why doesn't the compiler gives a warning when we try to fmap an effectful IO to an existing IO Monad?


回答1:


You're almost there. What is the type of fmap putStrLn?

putStrLn      ::              String -> IO ()
fmap          :: Functor f => (a -> b) -> f a -> f b    
fmap putStrLn :: Functor f => f String -> f (IO ())

And as a result fmap putStrLn getLine will be IO (IO ()), that is, an IO action, which contains another IO action. There's no need for a warning*, after all, this could be what you intended. The compiler cannot determine whether you wanted m (m a) or m a.

That's actually the power of a monad, it has an operation which enables you to join those actions:

join :: Monad m => m (m a) -> m a
-- join x = x >>= id

* except maybe for the missing type signature. You can tell GHC to warn you about those with -fwarn-missing-signatures. See warnings and sanity-checking.



来源:https://stackoverflow.com/questions/25012233/fmap-putstrln-getline-does-not-perform-io

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!