--- lam.types local types = {} local util = require "util" table.unpack = table.unpack or unpack --- Converting between types types.globalns = {} -- namespace types.Symbol = function (name, ns, aliases) ns = ns or types.globalns aliases = aliases or {} if ns[name] then return ns[name] end local sym = { name = name, aliases = aliases } ns[name] = sym for _,a in ipairs(aliases) do ns[a] = sym end local mt = { __type = "Symbol", __tostring = function (self) return self.name end, } return setmetatable(sym, mt) end types.Number = tonumber types.String = function (str) local s = { value = str, escape = function(self) return self:gsub("\"", "\\\"") end, } local mt = { __type = "String", __tostring = function (self) return string.format( "\"%s\"", self:escape()) end, } return setmetatable(s, mt) end types.Cons = function (a, b) assert(a ~= nil and b ~= nil, "Need two non-nil arguments in a pair") local s = { a, b } local mt = { __type = "Pair", __tostring = function (p) local out = {} local car, cdr = p[1], p[2] while cdr do table.insert(out, tostring(car)) if type(cdr) == "table" then car = cdr[1] cdr = cdr[2] else table.insert(out, ".") table.insert(out, cdr) break end end return "("..table.concat(out, " ")..")" end } return setmetatable(s, mt) end types.List = function (tbl) local function tolist(base, items) if #items == 0 then return base end return tolist( types.Cons(table.remove(items), base), items) end return tolist({}, tbl) end --- Determining types types.lamtype = function (x) if type(x) == "number" then return "Number" elseif getmetatable(x) and getmetatable(x).__type then return getmetatable(x).__type else return type(x) end end --- Type predicates types.isa = function (x, t) return types.lamtype(x) == t end --- return types