我需要在Haskell中使用main
的循环。我试过这个:
main :: IO ()
main =
do
putStrLn "do something"
main
以上代码是否采取正确的方法?这种无限递归会导致溢出吗?
答案 0 :(得分:37)
这很好;不会发生堆栈溢出。 Haskell中的堆栈溢出(实际上,任何非严格的语言)与其他语言中的堆栈溢出不同;它们是在没有评估它们的情况下积累大量价值而产生的,但你们并没有在这里积累任何东西;只是排序一系列无限的动作。您可以这样想:打印一行后,操作将被丢弃,控件直接传递到main
;没有任何东西保留在堆栈上,因为没有什么必须返回。
同样的原因是你可以在不耗尽内存的情况下迭代无限列表:当程序进一步向下列表时,垃圾收集器会回收先前的列表单元格,因为它们不再需要。在这种情况下,之前的顺序被回收,因为没有理由保留你已经执行过的动作。
也就是说,编写这个特定示例的更好方法是:
import Control.Monad
main :: IO ()
main = forever $ putStrLn "do something"
当然,如果您的循环有意终止,这将不起作用。 forever
本身是通过递归实现的,因此除了可读性之外没有任何其他好处。
答案 1 :(得分:2)
您观察到的是“尾调用消除/优化”的结果,这对Haskell来说并不特别。参见例如http://en.wikipedia.org/wiki/Tail_call