local function eval (prog, env) local env = env or {} local last for _, fn in ipairs (prog) do last = fn (env) end return last end local function force (env) return function (x) if type (x) == "function" then x = x (env) end return x end end local function keywords_for (apply) return function (word_list) local keywords = {} for _, word in ipairs (word_list) do keywords[word] = apply end return setmetatable (keywords, {__call = function (t, ...) return apply(...) end}) end end local function default (apply) return function (operations) return setmetatable (operations, {__call = function (t, ...) return apply (...) end}) end end local function let (var) local _let = function (val) return function (env) env[force (env) (var)] = force (env) (val) end end return keywords_for (_let) { "equal", "be" } end local function get (var) return function (env) return env[force (env) (var)] end end local function add (x) local _add = function (y) return function (env) return force (env) (x) + force (env) (y) end end return keywords_for (_add) { "to", "with" } end local function subtract (x) local _sub = function (y) return function (env) return force (env) (x) - force (env) (y) end end return default (_sub) { from = function (y) return function (env) return force (env) (y) - force (env) (x) end end, with = _sub } end local function show (val) local _show = function (env) print (force (env) (val)) end return _show end local function is (a) local _equals = function (b) return function (env) return force (env) (a) == force (env) (b) end end return default (_equals) { greater_than = function (b) return function (env) return force (env) (a) > force (env) (b) end end, less_than = function (b) return function (env) return force (env) (a) < force (env) (b) end end, } end local function when (cond) local _when_true = function (when_true) local _when_false = function (when_false) return function (env) if force (env) (cond) then return eval (when_true, env) else return eval (when_false, env) end end end return { otherwise = _when_false } end return _when_true end local function seed_rand () math.randomseed (os.time ()) end local function rand () return math.random () end local function return_with (value) return function (env) return value end end local function define (name) return function (bindings) return function (body) return function (env) env[force (env) (name)] = { bindings, body } end end end end local function call (name) return function (args) return function (env) local call_env = setmetatable({}, {__index = env}) local bindings, body = env[name][1], env[name][2] for i, binding in ipairs (bindings) do call_env[binding] = force (env) (args[i]) end return eval (body, call_env) end end end print eval { define "fib" { "n" } { when (is (get "n") .less_than (1)) { return_with (0) ; } .otherwise { when (is (get "n") (1)) { return_with (1) } .otherwise { let "n1" .equal (subtract (1) .from (get "n")) ; let "n2" .equal (subtract (2) .from (get "n")) ; add (call "fib" {get "n1"}) .with (call "fib" {get "n2"}) ; } } } ; show (call "fib" { 10 }) ; }