{"id":16260168,"url":"https://github.com/twolodzko/luali","last_synced_at":"2025-04-08T13:50:11.461Z","repository":{"id":66164757,"uuid":"572441214","full_name":"twolodzko/luali","owner":"twolodzko","description":"Minimal Scheme interpreter in Lua","archived":false,"fork":false,"pushed_at":"2022-12-05T08:55:59.000Z","size":25,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-14T10:18:27.907Z","etag":null,"topics":["lisp","lisp-interpreter","lua","scheme","scheme-interpreter"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/twolodzko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-30T09:30:13.000Z","updated_at":"2025-02-04T20:02:08.000Z","dependencies_parsed_at":"2023-04-05T11:15:58.925Z","dependency_job_id":null,"html_url":"https://github.com/twolodzko/luali","commit_stats":{"total_commits":1,"total_committers":1,"mean_commits":1.0,"dds":0.0,"last_synced_commit":"916284b94051bc95502a69a4e3a391e60a4292c5"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twolodzko%2Fluali","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twolodzko%2Fluali/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twolodzko%2Fluali/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twolodzko%2Fluali/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/twolodzko","download_url":"https://codeload.github.com/twolodzko/luali/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247855107,"owners_count":21007494,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lisp","lisp-interpreter","lua","scheme","scheme-interpreter"],"created_at":"2024-10-10T16:06:36.739Z","updated_at":"2025-04-08T13:50:11.408Z","avatar_url":"https://github.com/twolodzko.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Minimal Scheme implemented in Lua\n\n\u003e *Do It, Do It Again, and Again, and Again ...*  \n\u003e \u0026emsp; — *The Little Schemer* by Friedmann and Felleisen\n\n![Lisp cycles XKCD #297: \"Those are your father's parentheses. Elegant weapons for a more... civilized age.\"](https://imgs.xkcd.com/comics/lisp_cycles.png)\n\n(source \u003chttps://xkcd.com/297/\u003e)\n\n[Lua] is an interesting language. It is slightly older than JavaScript, though it never got even close to its popularity.\nIt has only [eight basic data types]. While lisps treat everything as lists, Lua treats everything as tables\n(aka maps or dictionaries in other languages). An [array] is a table, [classes] are tables of methods relating to a table\nof data values, etc. It is a multi-paradigm language, but like functional languages, it is [tail-call optimized].\nIt has some cool features, for example, when calling a function, the arguments that were [not provided] just default \nto `nil`. Also, a function can have multiple returns, but you can catch as many of them as you want. Calling\n`x, y = foo()` will assign the first two returned values to `x` and `y` regardless of the actual number of returns,\nwhereas if `foo()` returned less than two values, they will just be `nil`.\n\nTo mimic Scheme's types, I re-used the basic types for booleans, numbers (as crazy as it sounds, Lua\n[doesn't distinguish between number types]!), and strings. I use Lua's standard way of printing for\nvariables of those types, so strings are not quoted, and booleans are printed as `true` and `false` instead of `#t`\nand `#f` (unlike Scheme, both `true` and `#t` will evaluate to boolean true). Symbols and lists were implemented using\ncustom types. Like old-school JavaScript, Lua's approach to object-oriented programming and [classes] is by using\nprototypes. The symbol type got implemented as a `{ type = \"symbol\", name = \u003cname\u003e }` table.\nAdditionally, it has the `__eq` method for comparing symbols (are equal when having the same name) and `__tostring`\nfor pretty printing.\n\n```lua\nfunction Symbol(name)\n    local symbol = { type = \"symbol\", name = name }\n    setmetatable(symbol, {\n        __eq = function(x, y)\n            return x.name == y.name\n        end,\n        __tostring = function(o)\n            return o.name\n        end\n    })\n    return symbol\nend\n```\n\nScheme's lists, on other hand, are [linked lists] of the `{ type = \"list\", this = \u003chead\u003e, next = \u003ctail\u003e }` form. Where\n`\u003chead\u003e` is what you would get from `(car list)` and `\u003ctail\u003e` from `(cdr list)`. By doing so (instead of using\nLua's arrays), we can efficiently detach lists head or tail, prepend it, etc which are common operations in lisps.\n\nEnvironments are tables as well, `{ table = \u003crecords\u003e, parent = \u003cparent\u003e }`, has `\u003crecords\u003e` table of key-value\npairs for the local variable bindings, and `\u003cparent\u003e` is the reference to the enclosing environment (or `nil`).\nBecause Lua passes nearly everything [by references] we don't need to worry about the memory footprint here.\nWe can also rely on Lua's garbage collector to clean up not used environments for us.\n\nThe *[S-expressions]* are evaluated using the following rules\n\n```lua\nfunction eval.sexpr(sexpr, env)\n    if isquoted(sexpr) then\n        return sexpr.value\n    elseif issymbol(sexpr) then\n        return env:get(sexpr.name)\n    elseif islist(sexpr) then\n        return evallist(sexpr, env)\n    else\n        return sexpr\n    end\nend\n```\n\nScheme\\'s procedures are residing in a table of Lua functions. For example, `car` takes the first argument, a list,\nevaluates it, and returns the first element of the resulting list. Because Lua is dynamically typed, we don't need\nto worry about declaring the types here.\n\n```lua\nprocedures[\"car\"] = function(args, env)\n    local list = eval.sexpr(args.this, env)\n    return list.this\nend\n```\n\nFor a slightly more complicated example, `lambda` returns a function that evaluates its body within the local environment\ncreated by binding the arguments passed to the function (`callargs`), with the keys given in the lambda declaration\n(`vars`). The following code handles the Scheme's `((lambda (\u003cvars\u003e) \u003cbody\u003e) \u003ccallargs\u003e)` calls.\n\n```lua\nprocedures[\"lambda\"] = function(args, env)\n    local vars = args.this\n    local body = args.next\n    return function(callargs, callenv)\n        local localenv = env:branch()\n        initlambda(vars, callargs, callenv, localenv)\n        local _, result = eval.each(body, localenv)\n        return result\n    end\nend\n```\n\nInterestingly, the resulting code is still over 1.6x faster than MIT Scheme for *The Little Schemer* examples.\nWhile it is slower than Go or OCaml, it's very fast for an interpreted, dynamically typed language.\n\n\n [Lua]: http://www.lua.org\n [eight basic data types]: http://www.lua.org/pil/2.html\n [array]: http://www.lua.org/pil/11.1.html\n [classes]: http://www.lua.org/pil/16.html\n [tail-call optimized]: http://www.lua.org/pil/6.3.html\n [doesn't distinguish between number types]: http://www.lua.org/pil/2.3.html\n [linked lists]: http://www.lua.org/pil/11.3.html\n [by references]: https://stackoverflow.com/a/8431462/3986320\n [S-expressions]: https://en.wikipedia.org/wiki/S-expression\n [not provided]: http://www.lua.org/manual/5.4/manual.html#3.4\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwolodzko%2Fluali","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftwolodzko%2Fluali","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwolodzko%2Fluali/lists"}