{"id":22375890,"url":"https://github.com/stylewarning/cl-algebraic-data-type","last_synced_at":"2026-01-06T14:08:51.134Z","repository":{"id":140286182,"uuid":"120165478","full_name":"stylewarning/cl-algebraic-data-type","owner":"stylewarning","description":"Algebraic data types in Common Lisp","archived":false,"fork":false,"pushed_at":"2024-08-17T23:35:24.000Z","size":38,"stargazers_count":139,"open_issues_count":9,"forks_count":9,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-25T23:34:10.306Z","etag":null,"topics":["algebraic-data-types","common-lisp","functional-programming"],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stylewarning.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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}},"created_at":"2018-02-04T07:48:45.000Z","updated_at":"2025-02-07T02:45:02.000Z","dependencies_parsed_at":"2024-02-13T21:27:52.015Z","dependency_job_id":"a056f239-c9b8-4ccb-b437-4c552d5fa602","html_url":"https://github.com/stylewarning/cl-algebraic-data-type","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stylewarning%2Fcl-algebraic-data-type","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stylewarning%2Fcl-algebraic-data-type/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stylewarning%2Fcl-algebraic-data-type/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stylewarning%2Fcl-algebraic-data-type/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stylewarning","download_url":"https://codeload.github.com/stylewarning/cl-algebraic-data-type/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245708990,"owners_count":20659625,"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":["algebraic-data-types","common-lisp","functional-programming"],"created_at":"2024-12-04T21:28:09.052Z","updated_at":"2026-01-06T14:08:51.129Z","avatar_url":"https://github.com/stylewarning.png","language":"Common Lisp","readme":"# CL-ALGEBRAIC-DATA-TYPE\n*by Robert Smith*\n\n*This library provides an approximation of algebraic data types as in\nother functional languages. If you would like a complete solution to\nalgebraic data types with static types in Common Lisp, then consider\n[Coalton](https://github.com/coalton-lang/coalton) instead.*\n\nCL-ALGEBRAIC-DATA-TYPE, or ADT, is a library for defining algebraic\ndata types in a similar spirit to Haskell or Standard ML, as well as\nfor operating on them.\n\nWe can define ADTs using `defdata`:\n\n``` common-lisp\n(adt:defdata maybe\n  (just t)\n  nothing)\n```\n\nwhich will define a new type `maybe`, with a unary constructor `just`,\nand a nullary constructor `nothing`. The `t` represents the data type\nof that field.\n\n``` common-lisp\n\u003e (just 5)\n#.(JUST 5)\n\u003e nothing\n#.NOTHING\n```\n\nNote that the `#.` are printed so that they can be read back. This\nallows them to be used literally in quoted lists, for example.\n\n``` common-lisp\n\u003e '(#.(just 1) #.nothing)\n(#.(JUST 1) #.NOTHING)\n\u003e (typep (first *) 'maybe)\nT\n```\n\nIf this is annoying to you, you can set the variable\n`adt:*print-adt-readably*` to `nil`.\n\nWe can define our own version of a list via\n\n``` common-lisp\n(adt:defdata liszt\n  (kons t liszt)\n  knil)\n```\n\nwhich defines the binary constructor `kons` and the nullary constructor\n`knil`.\n\n``` common-lisp\n\u003e (kons 1 (kons 2 knil))\n#.(KONS 1 #.(KONS 2 #.KNIL))\n```\n\n\nAt the end we will define `kar` and `kdr`.\n\nFor efficiency, we might specify the types more exactly. For a `point`\ntype that supports rectangular and polar coordinates, which is also\nmutable, we might have:\n\n``` common-lisp\n(adt:defdata (point :mutable t)\n  (rectangular float float)\n  (polar float float))\n```\n\nThe `:mutable` option signifies that the data is mutable.\n\nWhen we have constructed a value, we can extract data out of it using `match`:\n\n``` common-lisp\n\u003e (let ((pt (rectangular 1.0 2.0)))\n    (adt:match point pt\n      ((rectangular x y) (+ x y))\n      ((polar _ _) nil)))\n3.0\n```\n\nIf we did not include the `polar` case, we would get a warning.\n\n``` common-lisp\n\u003e (let ((pt (rectangular 1.0 2.0)))\n    (adt:match point pt\n      ((rectangular x y) (+ x y))))\n; caught WARNING:\n;   Non-exhaustive match. Missing cases: (POLAR)\n3.0\n```\n\nWe can also specify a fall-through:\n\n``` common-lisp\n\u003e (let ((pt (rectangular 1.0 2.0)))\n    (adt:match point pt\n      ((rectangular x y) (+ x y))\n      (_ nil)))\n3.0\n```\n\nSince `point` is mutable, we can efficiently modify its fields using\n`set-data`.\n\n``` common-lisp\n\u003e (defun mirror-point! (pt)\n    (adt:with-data (rectangular x y) pt\n      (adt:set-data pt (rectangular y x))))\n\n\u003e (let ((pt (rectangular 1.0 2.0)))\n   (mirror-point! pt)\n   (adt:match point pt\n     ((rectangular x y) (format t \"point is (~A, ~A)\" x y))\n     (_ nil))\n```\n\nwill print `point is (2.0, 1.0)`.\n\nSee [examples.txt](examples.txt) for examples.\n\n\n## Frequently Asked Questions\n\n**Q.** How do we define `kar` and `kdr` for `liszt`?\n\n**A.** Easy.\n\n``` common-lisp\n(defun kar (l)\n  (adt:match liszt l\n    ((kons a _) a)\n    (knil knil)))\n\n(defun kdr (l)\n  (adt:match liszt l\n    ((kons _ b) b)\n    (knil knil)))\n```\n\n**Q.** Can I get the constructors dynamically for a particular ADT?\n\n**A.** Yes. You can get the constructors and associated arity by\ncalling the `get-constructors` function, which will return a list of\n`(\u003cconstructor\u003e \u003carity\u003e)` pairs. For example, given the `liszt`\nexample above, we have\n\n``` common-lisp\n\u003e (adt:get-constructors 'liszt)\n((KONS 2) (KNIL 0))\nT\n```\n\nThe second value `t` represents the fact that the ADT is known and\nexists.\n\n**Q.** I have an ADT defined, and I'd like to extend it with another\nADT. How can I do that?\n\n**A.** You can define a new ADT which includes another one. For\nexample, consider the following Boolean ADT.\n\n``` common-lisp\n(adt:defdata bool\n  true\n  false)\n```\n\nSuppose you wanted to extend this to have a \"fuzzy\" option, a\nprobability between true and false, specifically a `real` between `0`\nand `1` exclusive. We can create a `fuzzy-bool` which includes the\n`bool` type, as well as a unary `fuzzy` constructor. This is done by\nthe `:include` option to `defdata`.\n\n``` common-lisp\n(adt:defdata (fuzzy-bool :include bool)\n  (fuzzy (real (0) (1))))\n```\n\nNote that `true` and `false` are constructors for *both* `bool` and\n`fuzzy-bool`, as we can see with `get-constructors`.\n\n``` common-lisp\n\u003e (adt:get-constructors 'bool)\n((TRUE 0) (FALSE 0))\nT\n\u003e (adt:get-constructors 'fuzzy-bool)\n((TRUE 0) (FALSE 0) (FUZZY 1))\nT\n```\n\n**Q.** Can we do parametric ADTs like I can in Haskell?\n\n**A.** There is no support for it because Lisp doesn't have any useful\nnotion of definable parametric types that aren't aliases of another\nexisting parametric type.\n\n\n**Q.** Why doesn't deeper pattern matching work?\n\n**A.** It's not implemented, but it could be implemented for fields\nwhich are themselves algebraic data types. Patches welcome!\n","funding_links":[],"categories":["Miscellaneous ##"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstylewarning%2Fcl-algebraic-data-type","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstylewarning%2Fcl-algebraic-data-type","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstylewarning%2Fcl-algebraic-data-type/lists"}