在Haskell中永远理解

ven*_*ddy 1 monads haskell

目标:取一个字符串并在控制台中打印相同的东西,就像需要永远完成相同的操作一样

我提出了这样的事情,没有编译错误但没有按预期工作.

greet_buggy :: String -> IO ()
greet_buggy = forever $ putStrLn
Run Code Online (Sandbox Code Playgroud)

问题是在字符串下面没有在控制台中打印任何内容.

greet_buggy "something"
Run Code Online (Sandbox Code Playgroud)

基于这篇文章我尝试调试并更改了如下定义.它工作正常

greet :: IO ()
greet = forever $ putStrLn "Hello"
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释这里发生的事情吗?是否有可能forever单独使用相同的效果?

编辑:找到一个相关的帖子(感谢@Daniel Wagner),即使通过这个问题与我的不同,答案解释一下forever.

n. *_* m. 8

greet_buggy 正在为一个不同的monad工作.

forever采取一元行动并无限期地重复它.它可以这样定义:

forever a = let loop = a >> loop in loop
Run Code Online (Sandbox Code Playgroud)

也可以看作是

forever a = a >> a >> a >> a >> ...  (infinitely many times)
Run Code Online (Sandbox Code Playgroud)

(事实上​​永远是定义在Applicative,而不是Monad;但现在这并不重要).

所以forever greet实际上是

putStrLn "Hello" >> putStrLn "Hello" >> putStrLn "Hello" >> ...
Run Code Online (Sandbox Code Playgroud)

这不需要进一步解释.

OTOH forever greet_buggy相当于

putStrLn >> putStrLn >> putStrLn >> ...
Run Code Online (Sandbox Code Playgroud)

现在,因为(-> a)是一个monad,>>定义为任何两个合适类型的函数,f >> g在这种情况下的含义是......只是g!所以意义

( putStrLn >> putStrLn >> putStrLn >> ... ) "Hello"
Run Code Online (Sandbox Code Playgroud)

是采取链中的最后一个函数>>并将其应用于Hello.当然,那里没有最后的功​​能,所以这只是永远运行.