2012-07-20 37 views
2

我正在Lua中編寫一個小的CLI模塊以嵌入到C程序中。Lua tail-call vs loop

我想知道什麼是處理及時,尾調用之間選擇最佳的方法。

由於尾調用我會做這樣的事情:

call = { help=function() print 'just ask politely' end } 

function shell() 
    io.write ('% ') 
    local cmd = io.read() 

    if cmd ~= 'quit' then  
    call[cmd]() -- for simplicity assume call[cmd] is never nil 
    return shell() 
    end 
end 

我會問以下幾個問題:

  1. 它是一個正確的使用/執行尾調用的消除call[cmd]()是否在堆棧中引入了任何干擾,這樣我就不會利用尾呼消除

  2. 使用循環如下更好嗎?如果是,爲什麼?

    repeat 
        io.write ('% ') 
        local cmd = io.read() 
    
        -- do stuff 
    until cmd == 'quit' 
    
  3. 在在Lua編程陳述

    尾呼叫是裝扮成一個呼叫一個goto。

    那麼在tail調用和循環之間有什麼具體區別?

謝謝。

回答

10

這是一個正確的使用/執行尾部呼叫消除嗎?

如果您問到最後對shell的呼叫是否是根據Lua語法the answer is yes的正確尾部呼叫。

呼叫[cmd]()是否在堆棧中引入了任何干擾,這樣我就不會利用尾部呼叫消除了?

函數調用不會以您想要的方式修改堆棧。在Lua中,只有尾調用的要求是它的形式爲return Function(params),沒有額外的返回值不是函數的返回值。

適當的尾巴呼叫甚至不需要自己調用;它不需要遞歸。

使用如下循環更好嗎?如果是,爲什麼?

這是一個主觀觀點。就我個人而言,我會說這個循環對於發生的事情更加清楚。

但是,如果您想要一個客觀的性能問題,請考慮:尾部呼叫永遠不會比循環更快。就性能而言,絕對最好的選擇是平等的。

它可能不會是這樣。 Lua tail調用「優化」僅僅意味着它重用當前函數的堆棧條目。 Lua仍然需要從全局表中獲取函數。 Lua仍然需要完成所有調用函數的開銷;它只是不需要分配更多的堆棧內存。

這實際上不是溢出堆棧,並且不需要分配內存。

尾調用和循環之間有什麼具體區別嗎?

參見上文。

+0

你更清楚地解釋我的意思。 +1並刪除了我的答案。 – orlp 2012-07-20 20:19:48

+0

因此在很多情況下,Lua中的尾遞歸函數可能比循環函數慢。但考慮需要處理可變參數或多個返回值的情況。 '函數遞歸(N,I,總和,纈氨酸,...) \t如果n == i,那麼返回1 +總和端 \t返回遞歸(N,I + 1,總和+纈氨酸,...) 端'調用它作爲'recurse(n,1,...)'在香草Lua中,這比在表上循環要慢一些,但是不要忘記你必須創建,初始化並收集那個表當你完成時,每一次。在LuaJIT中,這個代碼實際上比在一個數組上循環更快*幾個數量級*。 – 2015-05-10 22:27:25

+0

對不起,應該是:'如果n == i然後返回val + sum end'。 – 2015-05-10 22:37:29