【发布时间】:2013-08-11 01:15:53
【问题描述】:
我正在尝试在 Haskell 中实现各种主循环,在 C 中我会这样写:
EntityInteraction *frame(Entity *eList, EntityInteraction *iList) {
parseInteractions(eList, iList);
return simulateEntities(eList);
}
int main() {
Entity eList[] = {...}
EntityInteraction *iList = NULL;
while(true) {
iList = frame(eList, iList);
}
}
所以我试图通过使 frame 成为递归函数来在 haskell 中复制它:
frame :: [Entity] -> [EntityInteraction] -> IO ()
frame eList iList = do
frame (parseInteractions iList eList) (simulateEntities eList)
main :: IO ()
main = do
let entList = [...]
frame entList []
但这只会导致预期的堆栈溢出,所以我的问题是在使用可变状态的 haskell 中执行主循环的正确方法是什么?
(我以 C 语言编程已经 4 年了,我刚刚开始学习 Haskell)
【问题讨论】:
-
这样的尾递归不应导致堆栈溢出。也许你
elist或ilist在某个时候变得太大了?另外,你是如何编译你的程序的?尝试使用ghc -O2以确保。 -
eList,并且 iList 永远不会被添加到。我尝试使用 -O2 开关,但它仍然给我消息:“main:内存不足”
-
也许你可以提供一个完整的、可编译的、最小的例子。我刚试过
main = frame;frame = return () >> frame,虽然这显然会烧毁 cpu,但它在恒定空间中快乐地永远运行(使用 800k 内存)。 -
完整的源代码在这里:pastebin.com/FrnyLb4e 它是一个功能纯实体系统,但目前它什么都不做
-
问题是你只是永远递归而没有输出(“观察”)任何东西。在递归调用
frame之前添加print,您会发现它运行良好。 (懒惰确实改变了“可变”状态的性质——即你正在构建 thunk 而不是计算任何东西——但你走在正确的轨道上,观察结果会有所帮助)