{"id":23467369,"url":"https://github.com/ucsd-progsys/elsa","last_synced_at":"2025-05-15T20:07:23.105Z","repository":{"id":18574224,"uuid":"84633944","full_name":"ucsd-progsys/elsa","owner":"ucsd-progsys","description":"Elsa is a lambda calculus evaluator ","archived":false,"fork":false,"pushed_at":"2025-03-26T02:36:03.000Z","size":93,"stargazers_count":187,"open_issues_count":1,"forks_count":23,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-13T11:16:58.786Z","etag":null,"topics":["haskell","haskell-learning","lambda-calculus","reduction"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ucsd-progsys.png","metadata":{"files":{"readme":"README.md","changelog":"changes.md","contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null}},"created_at":"2017-03-11T08:02:59.000Z","updated_at":"2025-04-29T22:52:08.000Z","dependencies_parsed_at":"2024-12-24T12:31:21.104Z","dependency_job_id":"c20b8d96-c5e8-46fb-99c8-76e3377bc18b","html_url":"https://github.com/ucsd-progsys/elsa","commit_stats":{"total_commits":62,"total_committers":8,"mean_commits":7.75,"dds":"0.27419354838709675","last_synced_commit":"00e0bb97326cce5329dee8652f1531a4ed111d19"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ucsd-progsys%2Felsa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ucsd-progsys%2Felsa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ucsd-progsys%2Felsa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ucsd-progsys%2Felsa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ucsd-progsys","download_url":"https://codeload.github.com/ucsd-progsys/elsa/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254414499,"owners_count":22067272,"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":["haskell","haskell-learning","lambda-calculus","reduction"],"created_at":"2024-12-24T12:30:55.441Z","updated_at":"2025-05-15T20:07:18.013Z","avatar_url":"https://github.com/ucsd-progsys.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ELSA\n\n`elsa` is a tiny language designed to build\nintuition about how the Lambda Calculus, or\nmore generally, _computation-by-substitution_ works.\nRather than the usual interpreter that grinds\nlambda terms down to values, `elsa` aims to be\na light-weight _proof checker_ that determines\nwhether, under a given sequence of definitions,\na particular term _reduces to_ to another.\n\n## Online Demo\n\nYou can try `elsa` online at [this link](https://elsa.goto.ucsd.edu/index.html)\n\n\n## Install\n\nYou can locally build and run `elsa` by\n\n1. Installing [stack](https://www.haskellstack.org)\n2. Cloning this repo\n3. Building `elsa` with `stack`.\n\nThat is, to say\n\n```bash\n$ curl -sSL https://get.haskellstack.org/ | sh\n$ git clone https://github.com/ucsd-progsys/elsa.git\n$ cd elsa\n$ stack install\n```\n## Editor Plugins\n\n- [VS Code extension](https://marketplace.visualstudio.com/items?itemName=akainth015.elsa-lang) with syntax highlighting and autocompletion support\n  - [Source](https://github.com/akainth015/vscode-elsa-lang)\n  - Contributed by [**@akainth015**](https://github.com/akainth015/), based on the [original version](https://github.com/mistzzt/vscode-elsa-lang) by [**@mistzzt**](https://github.com/mistzzt)\n- [Vim](https://github.com/glapa-grossklag/elsa.vim)\n\n## Overview\n\n`elsa` programs look like:\n\n```haskell\n-- id_0.lc\nlet id   = \\x -\u003e x\nlet zero = \\f x -\u003e x\n\neval id_zero :\n  id zero\n  =d\u003e (\\x -\u003e x) (\\f x -\u003e x)   -- expand definitions\n  =a\u003e (\\z -\u003e z) (\\f x -\u003e x)   -- alpha rename\n  =b\u003e (\\f x -\u003e x)             -- beta reduce\n  =d\u003e zero                    -- expand definitions\n\neval id_zero_tr :\n  id zero  \n  =*\u003e zero                    -- transitive reductions\n```\n\nWhen you run `elsa` on the above, you should get the following output:\n\n```bash\n$ elsa ex1.lc\n\nOK id_zero, id_zero_tr.\n```\n\n## Partial Evaluation\n\nIf instead you write a partial sequence of\nreductions, i.e. where the _last_ term can\nstill be further reduced:\n\n```haskell\n-- succ_1_bad.lc\nlet one  = \\f x -\u003e f x\nlet two  = \\f x -\u003e f (f x)\nlet incr = \\n f x -\u003e f (n f x)\n\neval succ_one :\n  incr one\n  =d\u003e (\\n f x -\u003e f (n f x)) (\\f x -\u003e f x)\n  =b\u003e \\f x -\u003e f ((\\f x -\u003e f x) f x)\n  =b\u003e \\f x -\u003e f ((\\x -\u003e f x) x)\n```\n\nThen `elsa` will complain that\n\n```bash\n$ elsa ex2.lc\n\nex2.lc:11:7-30: succ_one can be further reduced\n\n  11  |   =b\u003e \\f x -\u003e f ((\\x -\u003e f x) x)\n              ^^^^^^^^^^^^^^^^^^^^^^^^^\n```\n\nYou can _fix_ the error by completing the reduction\n\n```haskell\n-- succ_1.lc\nlet one  = \\f x -\u003e f x\nlet two  = \\f x -\u003e f (f x)\nlet incr = \\n f x -\u003e f (n f x)\n\neval succ_one :\n  incr one\n  =d\u003e (\\n f x -\u003e f (n f x)) (\\f x -\u003e f x)\n  =b\u003e \\f x -\u003e f ((\\f x -\u003e f x) f x)\n  =b\u003e \\f x -\u003e f ((\\x -\u003e f x) x)\n  =b\u003e \\f x -\u003e f (f x)                 -- beta-reduce the above\n  =d\u003e two                             -- optional\n```\n\nSimilarly, `elsa` rejects the following program,\n\n```haskell\n-- id_0_bad.lc\nlet id   = \\x -\u003e x\nlet zero = \\f x -\u003e x\n\neval id_zero :\n  id zero\n  =b\u003e (\\f x -\u003e x)\n  =d\u003e zero\n```\n\nwith the error\n\n```bash\n$ elsa ex4.lc\n\nex4.lc:7:5-20: id_zero has an invalid beta-reduction\n\n   7  |   =b\u003e (\\f x -\u003e x)\n          ^^^^^^^^^^^^^^^\n```\n\nYou can fix the error by inserting the appropriate\nintermediate term as shown in `id_0.lc` above.\n\n## Syntax of `elsa` Programs\n\nAn `elsa` program has the form\n\n```haskell\n-- definitions\n[let \u003cid\u003e = \u003cterm\u003e]+\n\n-- reductions\n[\u003creduction\u003e]*\n```\n\nwhere the basic elements are lambda-calulus `term`s\n\n```haskell\n\u003cterm\u003e ::=  \u003cid\u003e\n          \\ \u003cid\u003e+ -\u003e \u003cterm\u003e\n            (\u003cterm\u003e \u003cterm\u003e)\n```\n\nand `id` are lower-case identifiers            \n\n```\n\u003cid\u003e   ::= x, y, z, ...\n```\n\nA `\u003creduction\u003e` is a sequence of `term`s chained together\nwith a `\u003cstep\u003e`\n\n```haskell\n\u003creduction\u003e ::= eval \u003cid\u003e : \u003cterm\u003e (\u003cstep\u003e \u003cterm\u003e)*\n\n\u003cstep\u003e      ::= =a\u003e   -- alpha equivalence\n                =b\u003e   -- beta  equivalence\n                =d\u003e   -- def   equivalence\n                =*\u003e   -- trans equivalence\n                =~\u003e   -- normalizes to\n```\n\n\n## Semantics of `elsa` programs\n\nA `reduction` of the form `t_1 s_1 t_2 s_2 ... t_n` is **valid** if\n\n* Each `t_i s_i t_i+1` is **valid**, and\n* `t_n` is in normal form (i.e. cannot be further beta-reduced.)\n\nFurthermore, a `step` of the form  \n\n* `t =a\u003e t'` is valid if `t` and `t'` are equivalent up to **alpha-renaming**,\n* `t =b\u003e t'` is valid if `t` **beta-reduces** to `t'` in a single step,\n* `t =d\u003e t'` is valid if `t` and `t'` are identical after **let-expansion**.\n* `t =*\u003e t'` is valid if `t` and `t'` are in the reflexive, transitive closure\n             of the union of the above three relations.\n* `t =~\u003e t'` is valid if `t` [normalizes to][normalform] `t'`.\n\n\n(Due to Michael Borkowski)\n\nThe difference between `=*\u003e` and `=~\u003e` is as follows.\n\n* `t =*\u003e t'` is _any_ sequence of zero or more steps from `t` to `t'`. \n  So if you are working forwards from the start, backwards from the end, \n  or a combination of both, you could use `=*\u003e` as a quick check to see \n  if you're on the right track. \n\n* `t =~\u003e t'` says that `t` reduces to `t'` in zero or more steps **and** \n   that `t'` is in **normal form** (i.e. `t'` cannot be reduced further). \n   This means you can only place it as the *final step*. \n\nSo `elsa` would accept these three\n\n```\neval ex1:\n  (\\x y -\u003e x y) (\\x -\u003e x) b \n  =*\u003e b\n\neval ex2:\n  (\\x y -\u003e x y) (\\x -\u003e x) b \n  =~\u003e b\n\neval ex3:\n  (\\x y -\u003e x y) (\\x -\u003e x) (\\z -\u003e z) \n  =*\u003e (\\x -\u003e x) (\\z -\u003e z) \n  =b\u003e (\\z -\u003e z)\n```\n\nbut `elsa` would *not* accept \n\n```\neval ex3:\n  (\\x y -\u003e x y) (\\x -\u003e x) (\\z -\u003e z) \n  =~\u003e (\\x -\u003e x) (\\z -\u003e z) \n  =b\u003e (\\z -\u003e z)\n```\n\nbecause the right hand side of `=~\u003e` can still be reduced further.\n\n[normalform]: http://dl.acm.org/citation.cfm?id=860276\n[normalform-pdf]: http://www.cs.cornell.edu/courses/cs6110/2014sp/Handouts/Sestoft.pdf\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fucsd-progsys%2Felsa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fucsd-progsys%2Felsa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fucsd-progsys%2Felsa/lists"}