3

I was planning on writing a simple game to test out my understanding of functional programming. The functional way of doing the main loop, would be recursing it, but won't this eat up memory as more and more stack frames are generated?

Thanks

An example from How can you do anything useful without mutable state?

// 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を使用して関数を実装しました。つまり、への再帰呼び出しは関数の最後のものです。これにより、コンパイラー/インタープリター(言語によって異なります)は、現在のスタックフレームをすぐにポップし、再帰呼び出しのフレームに置き換えることができます。loop

簡単に言うと、実装方法では、スタックオーバーフローは発生せず、loop必要なだけ実行できます。

于 2012-08-22T11:29:52.063 に答える
0

Recursion is the new iteration :) Blog plug: http://blogs.msdn.com/b/ashleyf/archive/2010/02/06/recursion-is-the-new-iteration.aspx

You say you're using Clojure and would also be keen on knowing for F#.

It turns out that JVM-based languages (Java, Scala, Clojure, ...) can't support tail call optimization at the VM level and so have workarounds such as Clojure's recur. CLR-based languages (F#, C#, VB, ...) can and do use a .tail marker in the IL to cause early discarding of the stack frame.

Tail call optimization can make debugging a pain, so F# for example doesn't do it in debug builds (but does in release). There's a checkbox in project settings to enable in debug.

于 2012-08-22T14:39:40.663 に答える