簡短匿名函式 |
|
function() return ... end
,對於簡短函式來說感覺有點冗長,像是函數式程式風格中的 lambda 函式。舉例來說,在 Lua 中,像 map
函式 [1] 可使用如下方式:
local y = map(function(p) return translate[p] end, x)
在某些語言中,例如 Perl,可寫得更簡潔,像是:
my @y = map { $translate{$_} } @x;
my @y = @translate{@x};
以下是一些可替換 Lua 的方式。
我們可以透過公用函式 fn
來改善 Lua,它能從較短的字串表示式中建立匿名函式。可能像是這樣使用:
local y = map(fn("L1[P1]", translate), x)
fn
的參數包含表示式的字串表示形式,定義了要建立的匿名函式的回傳值,以及在表示式中稱為 L1
、L2
、L3
、...、L9
等的當地變數清單。匿名函式的參數使用 P1
、P2
、P3
、...、P9
表示。fn
可使用下列方式定義:
function fn(s, ...) local src = [[ local L1, L2, L3, L4, L5, L6, L7, L8, L9 = ... return function(P1,P2,P3,P4,P5,P6,P7,P8,P9) return ]] .. s .. [[ end ]] return loadstring(src)(...) end
這是執行此範例所需的其他程式碼:
function map(f, t) local t2 = {} for k,v in pairs(t) do t2[k] = f(v) end return t2 end local translate = {["hello"] = "hola", ["bye"] = "adi�s", ["sir"] = "se�or"} local t = map(fn("L1[P1]", translate), {"hello", "sir"}) print(table.concat(t, " ")) --> hola se�or
然而,請注意,如果 fn
重複使用在同一個字串化表示式上(例如在迴圈中),那會沒效率,因為每次呼叫都會喚起 loadstring
(需要產生程式碼)。這可透過 loadstring
編寫備忘錄(請參閱 FuncTables)來改善。這個基本模式(帶有備忘錄)用於 CodeGeneration 中。
如果匿名函式沒有當地變數,那麼語法會更短。例如,fn"P1 > 0"
是檢查參數是否大於 0 的函式。
有些人可能會建議支援任意數量的 Ln
和 Pn
變數;但記得,此技術僅適用於簡短的一行式表示式。
此外,在某些情況下,可以將字串->函式轉換移至 map 函式中來取得:
local y = map("P1 * 2", x)
以下是另一種語法:
getmetatable("").__call = function(s, ...) return assert(loadstring("return " .. s))()(...) end ("function(x,y) print(x+y) end")(2,3) -- prints 5
此處所述技術也稱為「字串 lambda」[1],它已實作於 JavaScript 和 Erlang 中
這方法有用,但不是很好,因為無法直接在 lambda 內使用詞彙變數。(一個可能的解決方案是 StringInterpolation。)
--DavidManura,2007-02
可透過 PenlightLibraries 取得字串 lambda 的實作。支援兩種形式,第一種類似是由 MetaLua 實作的,第二種則類似 Scala lambda
> require 'pl' > L = utils.string_lambda > = L'|x| x+2' (1) 3 > = L'_+2' (0) 2 > ls = List{'one','two','three'} > = ls:map(L'_:upper()') {ONE,TWO,THREE}
結果使用記事化模式快取。 原先,Penlight 中任何預期有一函式存在的函式都會傳遞一個字串,然後嘗試將該字串剖析為一個字串 lambda,但我們最後認為這會製造出過多的 magic。(這絕對適用於對字串 meta 函數的所有修改,以使它們直接可呼叫。)
Steve Donovan,2012 年
以下做法僅使用 Lua 進行原始碼篩選,因此它是完全獨立的
assert(loadstring((([[--filtered function pass(f) f() end function fail(f) if pcall(f) then error 'fail expected' end end pass << x = 1 + 2 >> fail << x = 1 + nil >> print 'DONE' ]]):gsub('<<', '(function(a,b) '):gsub('>>', ' end)'))))()
第一行中「[[]」之後應具有某些文字(例如「--」),以確保第一行會計算在任何錯誤訊息的行數中。還有,這行的文字會顯示在錯誤訊息中,因此最好應傳達某些意義。
以下是語法和執行時間錯誤的外觀
lua: src.lua:1: [string "--filtered..."]:4: 'then' expected near 'thenn' stack traceback: [C]: in function 'assert' src.lua:1: in main chunk [C]: ? $ lua src.lua lua: [string "--filtered..."]:6: attempt to call global 'Pass' (a nil value) stack traceback: [string "--filtered..."]:6: in main chunk src.lua:9: in main chunk [C]: ?
這種方法的一個缺點可能是,語法高亮顯示會將整個主程式碼標示為字串(不過,它在 XEmacs 中會正確標示顏色)。您可以透過對外部檔案執行loadfile
而不是loadstring
來變通解決此問題。
MetaLua [2] 提供|x,y| x*y
的語法,用於function(x,y) return x*y end
。
Lambda 函式補丁程式 [3] 透過補丁 Lua 剖析器提供相同的語法。
LuaPowerPatches 中的「do 補丁程式」使= do ... end
成為= function() ... end
的語法糖。
Lua
RiscLua 提供\
的語法糖,用於function
和=>
,用於return
。因此
curry = \(f) => \(x) => \(y) => f(x,y) end end end
LuaPowerPatches 中的簡潔匿名函式補丁程式使= [ ... ]
成為= function() ... end
的語法糖,並使= [| ... ]
成為= function() return ... end
的縮寫
Boost 等佔位符式表達式 (例如 tablex.map(_1*_1,{1,2,3,4}) --> {1,4,9,16}) 說明於「佔位符式表達式」中,請參考 [4]、LuaList:2009-03/msg00452.html 和 LuaList:2009-04/msg00069.html。