Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- gabriela-app.lua - application (as in "f(k)") and other extensions -- Author: Eduardo Ochs <[email protected]> -- Version: 2012mar30 -- Licence: GPL3 -- -- The latest upstream version of this can be found at: -- http://angg.twu.net/dednat5/gabriela-app.lua -- http://angg.twu.net/dednat5/gabriela-app.lua.html -- (find-dn5 "gabriela-app.lua") -- This depends on: -- http://angg.twu.net/dednat5/gabriela.lua -- http://angg.twu.net/dednat5/gabriela.lua.html -- (find-dn5 "gabriela.lua") -- Quick index: -- «.contexts» (to "contexts") -- «.contexts-test» (to "contexts-test") -- «.def-lambda-app» (to "def-lambda-app") -- «.comprehension» (to "comprehension") -- «.comprehension-test» (to "comprehension-test") -- «.def-lambda-app-tests» (to "def-lambda-app-tests") -- «.grids» (to "grids") -- «.grids-tests» (to "grids-tests") dofile "gabriela.lua" -- (find-dn5 "gabriela.lua") -- «contexts» (to ".contexts") -- Contexts are used for variables and for substitutions. Context = Class { type = "Context", __index = { push = function (ctxt, name, expr) local pair = {name, ctxt[name]} table.insert(ctxt.__stack, pair) ctxt[name] = expr return ctxt end, pop = function (ctxt) local pair = table.remove(ctxt.__stack) or error("Empty __stack") local name, oldvalue = pair[1], pair[2] ctxt[name] = oldvalue return ctxt end, minus = function (ctxt, name) if ctxt[name] == nil then return ctxt end ctxt = copy(ctxt); ctxt[name] = nil; return ctxt end, keys = function (ctxt) return sorted(keys(ctxt:minus("__stack"))) end, tostring = function (ctxt, sep) local ks = ctxt:keys() for i,name in ipairs(ks) do ks[i] = name.."="..tostring(ctxt[name]) end return mapconcat(id, ks, sep or ", ") end, print = function (ctxt) print(ctxt); return ctxt end, vprint = function (ctxt) print(ctxt:tostring"\n"); return ctxt end, }, __tostring = function (ctxt) return ctxt:tostring() end, } newcontext = function (T) T.__stack = {}; return Context(T) end context = newcontext {} defs = newcontext {} --[[ -- «contexts-test» (to ".contexts-test") -- Basic tests for contexts * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "gabriela-app.lua" c = newcontext {x=22, y=33} c:print() c:push("z", 44):print() c:push("x", 99):print() c:push("y", nil):print() PP(c) c:pop():print() c:pop():print() c:pop():print() c:pop():print() -- error --]] -- «def-lambda-app» (to ".def-lambda-app") -- A very simple implementation of definitions and application Def = function (name) return Expr {[0]="De", name} end App = function (e1, e2) return Expr {[0]="Ap", e1, e2} end Lambda = function (name, expr) return Expr {[0]="\\", name, expr} end Expr.__index.infix_other = function (e, b) local op, e1, e2, e3 = e[0], e[1], e[2], e[3] local t, str if op == "De" then t, str = 200, e1 elseif op == "Ap" then t, str = 200, e1:infix(3).."("..e2:infix()..")" elseif op == "\\" then t, str = 3, "\\"..e1.."."..e2:infix() -- Bonus: set comprehension -- subset, set of images, generator, filter, collect elseif op == "Cs" then t, str = 200, "{"..e1:infix().." | ".. e:infixs(", ", 2, #e-1).."}" elseif op == "Ci" then t, str = 200, "{"..e[#e]:infix().." | ".. e:infixs(", ", 1, #e-1).."}" elseif op == "Cg" then t, str = 200, e1:infix().." in "..e2:infix() elseif op == "Cf" then t, str = 200, e1:infix() elseif op == "Co" then t, str = 200, e1:infix() -- all other things else error("Bad expr") end return str, t end Expr.__index.eval_other = function (e) local op, e1, e2, e3 = e[0], e[1], e[2], e[3] if op == "De" then return defs[e1]:eval() elseif op == "\\" then return e elseif op == "Ap" then return _app(e1:eval(), e2:eval()) elseif op == "Cs" then return _evalcompr(e) elseif op == "Ci" then return _evalcompr(e) else print(tolisp(e)); error("Bad expr") end end _app = function (f, a) if otype(f) ~= "Expr" then error("f must be an expr") end if otype(a) ~= "Expr" then error("a must be an expr") end local f0, fvarname, fexpr = f[0], f[1], f[2] if f0 ~= "\\" then error("f must be a lambda form") end context:push(fvarname, a) local result = fexpr:eval() context:pop() return result end --[[ -- «def-lambda-app-tests» (to ".def-lambda-app-tests") -- Basic tests for lambda and app * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "gabriela-app.lua" f = Lambda("x", x + _2) f7 = App(f, _3 + _4) f:print() f:peval() f7:print() f7:lprint() f7:rprint() f7:peval() P = Def "P" defs.P = Lambda("x", Le(x, _2)) App(P, _1):peval() App(P, _2):peval() App(P, _3):peval() --]] -- «comprehension» (to ".comprehension") -- Inspired by: -- (find-es "haskell" "comprehension") -- http://www.haskell.org/tutorial/goodies.html#tut-list-comps -- http://www.haskell.org/onlinereport/exps.html#list-comprehensions -- http://www.haskell.org/haskellwiki/List_comprehension -- http://en.wikipedia.org/wiki/List_comprehension Subset = function (...) return Expr {[0]="Cs", ...} end Setof = function (...) return Expr {[0]="Ci", ...} end Gen = function (var, set) return Expr {[0]="Cg", var, set} end Filt = function (expr) return Expr {[0]="Cf", expr} end Collect = function (expr) return Expr {[0]="Co", expr} end _evalcompr_ = function (e, i) local op, e1, e2 = e[i][0], e[i][1], e[i][2] if op == "Co" then _collect(e1:eval()) elseif op == "Cf" then if not e1:beval() then return end _evalcompr_(e, i+1) elseif op == "Cg" then local varname = e1[1] local set = e2:seval() -- print(tolisp(varname), tolisp(e2), tolisp(set)) for _,value in ipairs(set) do context:push(varname, value) _evalcompr_(e, i+1) context:pop() end else print(i, op, e1, e2); error("what?") end end _evalcompr = function (e) local old_collect = _collect local results = Set() _collect = function (e) table.insert(results, e) end _evalcompr_(e, 1) _collect = old_collect return results end --[[ -- «comprehension-test» (to ".comprehension-test") * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "gabriela-app.lua" _10 = Num(10) A = Set(_1, _2, _3) B = Setof(Gen(x, A), Gen(y, A), Filt(Le(x, y)), Collect(_10*x+y)) C = Setof(Gen(x, A), Gen(y, A), Filt(Le(x, y)), Collect(Tuple(x, y))) D = Subset(Gen(x, A), Filt(Neq(x, _2)), Collect(x)) Setof(Gen(x, A), Collect(Tuple(x, x*x))):preval() B:preval() C:preval() D:preval() --]] -- «grids» (to ".grids") -- Some functions to create tables. -- Too many things are hardcoded at the moment. -- k = Var "k" P = Def "P" withdef = function (name, def, expr) defs:push(name, def) local result = expr:eval() defs:pop() return result end cell = function (x, y) if y == 1 then return Cols[x] end if x == 1 then return Ps[y-1] end return withdef("P", Lambda("k", Ps[y-1]), Cols[x]) end column = function (x) local C = Rect {w=0} for y=1,#Ps+1 do C:set(y, cell(x, y):infix()) end return C end columns = function (x1, x2) x1 = x1 or 1 x2 = x2 or #Cols local result = column(x1) for x=x1+1,x2 do result = result.." "..column(x) end return result end efold = function (f, a, ...) local result = a for _,b in ipairs {...} do result = f(result, b) end return result end Ors = function (...) return efold(Or, ...) end Ands = function (...) return efold(And, ...) end P1, P2, P3, P4 = App(P, _1), App(P, _2), App(P, _3), App(P, _4) defs.E_1 = Ors ( P2, P3 ) defs.E_2 = Ors (P1, P2, P3, P4) defs.E_3 = Ands( P2, P3 ) defs.E_4 = Ands(P1, P2, P3, P4) defs["E'_1"] = Or (Ors (P1, P2, P3), Ors (P2, P3, P4)) defs["E'_2"] = And(Ors (P1, P2, P3), Ors (P2, P3, P4)) defs["E'_3"] = Or (Ands(P1, P2, P3), Ands(P2, P3, P4)) defs["E'_4"] = And(Ands(P1, P2, P3), Ands(P2, P3, P4)) P123or = Ors (P1, P2, P3) P123and = Ands(P1, P2, P3) P234or = Ors (P2, P3, P4) P234and = Ands(P2, P3, P4) P123or = Ex(k, Set(_1, _2, _3), App(P, k)) P123and = Fa(k, Set(_1, _2, _3), App(P, k)) P234or = Ex(k, Set(_2, _3, _4), App(P, k)) P234and = Fa(k, Set(_2, _3, _4), App(P, k)) defs["E'_1"] = Or (P123or, P234or) defs["E'_2"] = And(P123or, P234or) defs["E'_3"] = Or (P123and, P234and) defs["E'_4"] = And(P123and, P234and) Cols = { App(P, k), P1, P2, P3, P4, Def("E_1"), Def("E_2"), Def("E_3"), Def("E_4"), } Ps = { Ge( k, _2), Ge( _2*k, _2), Eq( k, _1), Lt( k, _1), Neq( k, _2), Neq( k, _3), And(Neq(k, _2), Neq(k, _3)), Neq( k, _0), } --[[ -- «grids-tests» (to ".grids-tests") -- Test the code for drawing tables * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "gabriela-app.lua" defs:vprint() print(columns()) Cols = { App(P, k), P1, P2, P3, P4, False, Def("E_4"), Def("E'_3"), Def("E_3"), Def("E_1"), Def("E'_2"), Def("E_2"), True, } Ps = { False, Ge(k, _4), Or(Eq(k, _1), Eq(k, _4)), Ge(k, _3), Or(Eq(k, _2), Eq(k, _3)), Ge(k, _2), True, } defs:vprint() = columns() --]] -- Local Variables: -- coding: raw-text-unix -- ee-anchor-format: "«%s»" -- End: