Method Curry |
|
foo:bar()
) 不包含呼叫部分 (foo:bar
) 也能評估出 curried 閉包。當前我們有下列語意:
function object:wrap(method_name) local f = self[method_name] return function(...) return f(self, ...) end end
不過假如能直接寫成這樣,不是更好嗎?
f = foo:wrap("bar")
我們可以這樣寫:
f = foo:bar;
Slact 想到了這個點子,我也對剖析程式碼動了些腦筋,看看實作起來有多容易。
優點:與現有程式碼完全相容,提供一個簡單的方法,用已存在語法來使用匿名的函式。
缺點:每次方法呼叫時都會建立一個新的封閉,嚴重影響效能。可能需要最佳化這些部分,並只在下一段不是參數清單(表示將儲存而非呼叫它)時才建立閉包。
在純粹的 Lua 中測試時,包覆 wrap(foo, 'bar')
與直接呼叫 nowrap(foo,'bar') -- 給無作用函式nowrap
的速度差異達到 106%。如果純粹 Lua 中的測試結果可以反映在剖析程式碼中進行編碼時的效能影響,那保留當前的方法呼叫後檢查參數以進行最佳化的方式,可能就有意義了。
備註
-- on changes to the grammar <ToxicFrog> Hmm. I think this changes primaryexp from: prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } to prefixexp { '.' NAME | '[' exp ']' | ':' NAME | funcargs } -- on the emitted code <ToxicFrog> Table at 0 <ToxicFrog> SELF 0 0 <<field>> <ToxicFrog> CLOSURE 2 <<wrapper>> <ToxicFrog> MOVE 0 0 <ToxicFrog> MOVE 0 1 <ToxicFrog> CLOSE 0 <ToxicFrog> And then some stack cleanup. (FIXME: do I fully understand what CLOSE does?) <ToxicFrog> And <<wrapper>> is a function that looks like: <ToxicFrog> GETUPVAL 1 0 <ToxicFrog> GETUPVAL 2 1 <ToxicFrog> VARARG 3 0 <ToxicFrog> TAILCALL <ToxicFrog> 1 0 0 <ToxicFrog> RETURN 0 0 <ToxicFrog> So, the problems that need to be solved: <ToxicFrog> - emitting <<wrapper>> into the generated chunk <ToxicFrog> - making the stack consistent after we generate the closure </pre>
所有有趣的部份都在 lparser.c 中。需要變更 primaryexp 的程式碼產生。需要執行的兩個主要動作:如果我們有 foo:bar 結構,它需要發出在堆疊頂端留下閉包的程式碼 - 大部分都在上面寫了,但需要在完成後做一些清理。此外,實際的函式必須出現在常數表中。我們有以下三個選項
最後一個選項可能是最容易的,但可能會產生許多重複的函式 - 需要測試這個