{"id":16617258,"url":"https://github.com/pixelcmtd/clac","last_synced_at":"2026-04-27T04:31:18.326Z","repository":{"id":50592143,"uuid":"411774862","full_name":"pixelcmtd/clac","owner":"pixelcmtd","description":"λ Rust implementation of the Lambda Calculus.","archived":false,"fork":false,"pushed_at":"2022-12-09T06:04:31.000Z","size":2812,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"daddy","last_synced_at":"2025-12-26T16:37:34.208Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pixelcmtd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-29T17:47:06.000Z","updated_at":"2025-02-17T05:58:22.000Z","dependencies_parsed_at":"2023-01-25T17:01:20.502Z","dependency_job_id":null,"html_url":"https://github.com/pixelcmtd/clac","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pixelcmtd/clac","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixelcmtd%2Fclac","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixelcmtd%2Fclac/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixelcmtd%2Fclac/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixelcmtd%2Fclac/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pixelcmtd","download_url":"https://codeload.github.com/pixelcmtd/clac/tar.gz/refs/heads/daddy","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixelcmtd%2Fclac/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32323211,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-10-12T02:15:58.817Z","updated_at":"2026-04-27T04:31:18.310Z","avatar_url":"https://github.com/pixelcmtd.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# λ\n\n### also known as `clac`\n\nThis is an implementation of the λ-calculus in Rust. It has a few niceties to\nmake it more of a usable programming language. As a mathematician/computer\nscientist, you should be familiar with the basic syntax: `λa.a` is the Identity\nfunction (also known as `I`, „Identitätsfunktion“, “Idiot”). We also support the\nshortened syntax, so that `λa b.a` is the Kestrel (also known as `K`, `C`,\n„Konstante Funktion“, “Constant Function”). It is transparently π-expanded to\n`λa.λb.a` by the parser. Additionally, you can assign variables: `I ← λa.a`,\n`😈 ⇐ (λf.ff)(λf.ff)`. As you can see, `😈` is initialized using the expression\n`(λf.ff)(λf.ff)` instead of `(λf.f f)(λf.f f)`, which is because `⇐` activates\nthe single-letter-form (aka. math-form).\n\n\u003e But how do you run programs using this notation?\n\nThat’s pretty simple: You mutate it, in different ways. The normal computations\nare done using β-reduction, but the other procedures are also important.\n\n## α-renaming\n\nThis is probably the most complicated algorithm as there is no obvious approach.\n\nTake the identity function `λa.a`. It can also be expressed as `λb.b`, `λc.c`,\n`λα.α`, `λÄ.Ä`, `λᴍʏᴠᴀʀɪᴀʙʟᴇ.ᴍʏᴠᴀʀɪᴀʙʟᴇ`, `λ🏳️‍⚧️.🏳️‍⚧️`, or any other way to\nreplace `a` everywhere in the function. This works as long as our new symbol\ndoesn't appear freely in our original function. For example, α-renaming a\nfunction `λa.λb.a` to `λa.λa.a` is wrong, because `a` is free in `λb.a`.\n\nThis might seem simple, but, as I already said, it isn't. The difficult part is\ndetermining, where to α-rename to which variable names. That has no standard\nsolution.\n\n## β-reduction\n\nThe most important part.\n\nTake the term `(λa.a)(λb.b)`. It being β-reduced is commonly written as\n`(a)[a := (λb.b)]`, which results in `λb.b`.\n\nIn a general way, the term `(λx.f x)y` is β-reduced to `f y`.\n\nTo give you another example, let's add one and one:\n\n```λ\n+ 1 1 = (λm n f x . m f (n f x))(λf x.f x)(λf x.f x)\n→ (λn f x . (λf x.f x) f (n f x))(λf x.f x)\n→ λf x . (λf x.f x) f ((λf x.f x) f x)\n→ λf x . (λx.f x) ((λx.f x) x)\n→ λf x . (λx.f x) (f x)\n→ λf x . f (f x) = 2\n```\n\n## η-reduction\n\nThis is quite simple, you might also know it as “point-free programming”.\n\nA function `λx.f x` can be written as `f`. That's it!\n\nA real world example: You want a function for adding two. The obvious solution\nwould be `λ x . + 2 x`. But if you want to feel like a **real** badass hacker,\nyou can write it as `+ 2`.\n\nMost Haskell linters even force you to write your code this way, and you should.\n\n## ι-expansion\n\nThis one implements unsigned integers aka natural numbers.\n\nWhen [β-reducing](#β-reduction), integers are automatically ι-expanded like\nthis:\n\n```\nnum = Σ(\"x\")\nwhile i \u003e 0:\n  num = Α(Σ(\"f\"), num)\n  i--\nreturn Λ(\"f\", Λ(\"x\", num))\n```\n\nThis gives you the correct Church encodings for all unsigned integers:\n\n- 0 → `λf x.x`\n- 1 → `λf x.f x`\n- 2 → `λf x.f (f x)`\n- …\n\n## π-expansion\n\nHere, functions with multiple parameters are converted into proper λ-calculus.\n\nFor example, the function `λa b.a` is expanded into `λa.λb.a`.\n\nIt works like this:\n\n```\nfunc = body\nfor param in params.reverse():\n  func = Λ(param, func)\nreturn func\n```\n\n## Implementation details\n\n\u003c!--TODO: document the AST format better--\u003e\n\nWe use `pest` to parse your statements into a high-level AST, then we generate\nproper ASTs from that. Those basically look like that:\n\n\u003cimg src=\"Η.PNG\" width=\"250\" /\u003e\n\n`λa b.a b` η-reduces to `λa.a`.\n\nHere's how to add 1 and 1 using β-reduction:\n\n![](Β.PNG)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpixelcmtd%2Fclac","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpixelcmtd%2Fclac","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpixelcmtd%2Fclac/lists"}