fmap putStrLn getLine不执行IO

Eva*_*ian 4 haskell

实际上,标题就是这么说的.我无法理解为什么以下代码实际上不打印"Hello World"而不是什么>>=.

main = fmap putStrLn getLine
Run Code Online (Sandbox Code Playgroud)

目前,这是我的推理,请检查它是否有任何谬误.

如果我们比较fmap>>=

(>>=) :: Monad m => m a -> (a -> m b) -> m b
fmap :: Functor f => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

在绑定,上下文或IO术语"世界"中,第一个m和第二个m除了类型之外完全不同.(a -> m b)基本上重新创造了一个新的"世界".在Functor中不是这样,上下文f是相同的,因此副作用是不可能的.

现在,如果确实如此,为什么当我们尝试对fmap现有的IO Monad进行有效的IO 时,编译器不会发出警告?

Zet*_*eta 14

你快到了.是什么类型的fmap putStrLn

putStrLn      ::              String -> IO ()
fmap          :: Functor f => (a -> b) -> f a -> f b    
fmap putStrLn :: Functor f => f String -> f (IO ())
Run Code Online (Sandbox Code Playgroud)

结果fmap putStrLn getLineIO (IO ())是一个IO动作,它包含另一个 IO动作.毕竟,这不需要警告*,这可能是你想要的.编译器无法确定您是否需要m (m a)m a.

这实际上是monad的强大功能,它有一个操作可以让你加入这些动作:

join :: Monad m => m (m a) -> m a
-- join x = x >>= id
Run Code Online (Sandbox Code Playgroud)

*除了可能缺少的类型签名.你可以告诉GHC警告你-fwarn-missing-signatures.请参阅警告和健全检查.

  • @leftaroundabout我已经看到类型为"IO(IO a)"的(子表达式)自然出现并发性; 在锁定(或在某个其他关键部分)时,您计算在释放锁定后执行的操作(或者保留关键部分). (2认同)