3

我打算写一个简单的游戏来测试我对函数式编程的理解。执行主循环的功能方式是递归它,但是随着越来越多的堆栈帧的生成,这不会占用内存吗?

谢谢

没有可变状态的情况下如何做任何有用的事情?

// imperative version
pacman = new pacman(0, 0)
while true
    if key = UP then pacman.y++
    elif key = DOWN then pacman.y--
    elif key = LEFT then pacman.x--
    elif key = UP then pacman.x++
    render(pacman)

// functional version
let rec loop pacman =
    render(pacman)
    let x, y = switch(key)
        case LEFT: pacman.x - 1, pacman.y
        case RIGHT: pacman.x + 1, pacman.y
        case UP: pacman.x, pacman.y - 1
        case DOWN: pacman.x, pacman.y + 1
    loop(new pacman(x, y))
4

2 回答 2

5

您已经loop使用tail recursion实现了您的函数,即递归调用loop是函数中的最后一件事。这允许编译器/解释器(取决于语言)立即弹出当前堆栈帧并将其替换为递归调用的帧。

长话短说,您实现它的方式,不会有堆栈溢出,并且loop可以根据需要运行。

于 2012-08-22T11:29:52.063 回答
0

递归是新的迭代 :) 博客插件:http: //blogs.msdn.com/b/ashleyf/archive/2010/02/06/recursion-is-the-new-iteration.aspx

您说您正在使用 Clojure,并且还热衷于了解 F#。

事实证明,基于 JVM 的语言(Java、Scala、Clojure 等)无法支持 VM 级别的尾调用优化,因此有诸如 Clojure 之类的变通方法recur。基于 CLR 的语言(F#、C#、VB...)可以并且确实.tail在 IL 中使用标记来导致堆栈帧的提前丢弃。

尾调用优化会使调试变得痛苦,例如 F# 在调试版本中不会这样做(但在发布时会这样做)。项目设置中有一个复选框可以在调试中启用。

于 2012-08-22T14:39:40.663 回答