为什么`print <$>(print“ hello”)`打印“ hello”?


14

IO (IO ())同时计算(IO ())和时(),为什么

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

打印

"Hello, World!"

IO "Hello, World!" -- ??
"Hello, World!"

3
基本上fmap print (print "Hello World")将其第一个参数(print函数)应用于的结果print "Hello World"。这完全等同于执行操作print ()后调用print "Hello World"
Redu

@Redu是正确的,但是请注意,print ()永远不会评估其调用,也不会执行其操作(将()在stdout上打印)。因此,“ print ()在...之后调用”有点误导(IMO)。
chi

Answers:


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

由于单子法则,等价于

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

现在,print始终返回()结果,因此整个代码等效于

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

最后,main只需丢弃的结果。也就是说,最后一行可能会return (putStrLn "this is ignored")具有相同的效果。

因此,代码将只执行first print "Hello, World!"

我建议您始终定义main :: IO ()。Haskell允许我们声明main :: IO AnyTypeHere,但这(IMO)令人困惑。

我还建议您使用putStrLn,而不要print打印字符串,因为后者将引用并转义整个字符串。


5
我要补充的f <$> a ≡ a >>= \r -> return $ f r是,这不仅是这种情况的具体内容,而且实际上适用于任何monad。
左右左转
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.