Skip to content

Instantly share code, notes, and snippets.

@jcmoyer
Last active August 29, 2015 14:20
Show Gist options
  • Select an option

  • Save jcmoyer/6057bccaa3c0e1315682 to your computer and use it in GitHub Desktop.

Select an option

Save jcmoyer/6057bccaa3c0e1315682 to your computer and use it in GitHub Desktop.
(Lua 5.3) String-lambdas that close over locals with syntax inspired by OCaml/F#
-- taken from http://lua-users.org/wiki/StringTrim
local function trim(s)
return s:match "^%s*(.-)%s*$"
end
-- creates a function from a lambda string
local function fun(text)
-- divide the text into arg list and return body
local a, r = text:match("(.-)->(.*)")
a = trim(a)
r = trim(r)
-- we use a local, named function so that lambdas can recursively call themselves
local src = string.format([[-- %s
local function fun(%s) return (%s) end
return fun
]],
text, a:gsub('%s+', ','), r)
local fe = {}
-- first, inject the current _ENV
for k,v in pairs(_ENV) do
fe[k] = v
end
-- now crawl up the stack and inject any locals we find
local f = 2
local i = 1
local name, val = debug.getlocal(f, i)
while name do
fe[name] = val
i = i + 1
name, val = debug.getlocal(f, i)
-- try going up one more level
if not name then
if debug.getinfo(f + 1) then
f = f + 1
i = 1
else
break
end
end
end
local chunk = assert(load(src, nil, 't', fe))
return chunk()
end
-- recursive factorial lambda
local factorial = fun[[a s -> a > 0 and fun(a - 1, (s or 1) * a) or (s or 1)]]
-- maps a function over an array table
local function map(f, t)
local r = {}
for i = 1, #t do
r[i] = f(t[i])
end
return r
end
-- calling a local function being closed over
local results = map(fun[[a -> factorial(a)]], {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
print(table.unpack(results))
-- closures really work
local function f(x)
local y = 2
-- although for some reason, the only way to force x and y to show up in
-- debug.getlocal is to return one of them
return fun[[a -> a * x + y]], x, y
end
-- prints 17
print(f(3)(5))
-- calling functions from a global table
local cos = map(fun[[a -> math.cos(a)]], {0, math.pi / 2, math.pi, math.pi * 2})
print(table.unpack(cos))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment