在Haskell中使用什么而不是主循环?

sno*_*now 29 haskell

我需要main在Haskell中使用循环.我试过这个:

main :: IO ()
main =
  do
    putStrLn "do something"
    main
Run Code Online (Sandbox Code Playgroud)

上面的代码是正确的方法吗?这种无限递归会导致溢出吗?

ehi*_*ird 38

这可以; 不会发生堆栈溢出.Haskell中的堆栈溢出(实际上,任何非严格的语言)与其他语言中的堆栈溢出不同; 它们是在没有评估它们的情况下积累大量价值而产生的,但你们并没有在这里积累任何东西; 只是排序一系列无限的动作.您可以这样想:打印线后,操作被丢弃,控制直接进入main; 堆栈中没有任何东西,因为没有什么必须返回.

这就是你可以在不耗尽内存的情况下迭代无限列表的原因相同:当程序进一步向下列表时,垃圾收集器会回收先前的列表单元,因为它们不再需要.在这种情况下,之前的顺序被回收,因为没有理由保留您已执行的操作.

也就是说,编写这个特定示例的更好方法是:

import Control.Monad

main :: IO ()
main = forever $ putStrLn "do something"
Run Code Online (Sandbox Code Playgroud)

当然,如果您的循环有意终止,这将不起作用.forever它本身是用递归实现的,所以除了可读性之外没有任何好处.

  • @ChrisKuklewicz:实际上,Haskell并不保证尾调用优化,实际上编写一个导致堆栈溢出的尾递归Haskell程序是完全可能的.但是有一个[密切相关的概念](http://www.haskell.org/haskellwiki/Tail_recursion)确实适用,通常称为[tail recursion modulo cons](http://en.wikipedia.org/wiki/Tail_call #Tail_recursion_modulo_cons).尽管如此,它只是一个实现细节; Haskell报告根本没有详细说明评估策略. (6认同)
  • 此外,`main`中的`main`调用不在尾部位置,因为定义是`main =(>> =)(putStrLn"do something")main`.所以它是`(>> =)`是由`main`调用的尾.IO monad中`(>> =)`的定义可能会也可能不会调用它的第二个参数.也就是说,我希望递归能够在不增加堆栈的情况下运行. (5认同)
  • 奥古斯丁,应该是`(>>)`? (3认同)