永远的monad如何运作?
forever :: (Monad m) => m a -> m b
forever a = a >> forever a
如果我写
main = forever $ putStrLn "SAD, I DON'T UNDERSTAND!"
永远得到IO(),这不是函数,怎么能永远反复调用putStrLn?
答案 0 :(得分:11)
从forever
函数的定义,您可以看到它是一个标准的递归函数。
forever :: (Monad m) => m a -> m b
forever a = a >> forever a
那里没有魔法。 forever
只是一个递归函数。在您的特定情况下,这是一个非终止的。但是它是终止还是非终止取决于如何为该类型定义Monad。
检查>>
的类型,我们得到:
λ> :t (>>)
(>>) :: Monad m => m a -> m b -> m b
从中你可以看到输入m a
被忽略了。另一种思考方式是>>
函数只执行传递给它的第一个参数的副作用。在您的情况下,m a
将与IO ()
对应,因为这是putStrLn
的类型。
由于IO形成Monad,forever
函数也可以作用于IO
相关函数。
答案 1 :(得分:3)
要做的区别是putStrLn "SAD, I DON'T UNDERSTAND!"
是动作,而不仅仅是一个值。它重复执行动作。每当评估IO a
类型的某些内容时,它会执行其内部操作,然后返回包含在a
上下文中的IO
类型的内容。它不必为动作采取参数来做某事。例如,查看time
包中的getCurrentTime
函数。它只有IO UTCTime
类型,但如果你多次调用它,你会得到不同的值,即使它没有参数。