{"id":17249949,"url":"https://github.com/seancribbs/datalog-elixir","last_synced_at":"2025-04-14T05:31:34.034Z","repository":{"id":66403377,"uuid":"330788412","full_name":"seancribbs/datalog-elixir","owner":"seancribbs","description":"Naively-evaluated Datalog, implemented in Elixir","archived":false,"fork":false,"pushed_at":"2024-09-12T03:14:06.000Z","size":7,"stargazers_count":31,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2025-04-13T10:54:53.042Z","etag":null,"topics":["datalog","elixir"],"latest_commit_sha":null,"homepage":"","language":"Elixir","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/seancribbs.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":"2021-01-18T21:14:00.000Z","updated_at":"2024-11-19T20:59:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"fbf82219-663f-407d-898d-b897ce7cd63a","html_url":"https://github.com/seancribbs/datalog-elixir","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/seancribbs%2Fdatalog-elixir","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seancribbs%2Fdatalog-elixir/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seancribbs%2Fdatalog-elixir/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seancribbs%2Fdatalog-elixir/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seancribbs","download_url":"https://codeload.github.com/seancribbs/datalog-elixir/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248826593,"owners_count":21167718,"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":["datalog","elixir"],"created_at":"2024-10-15T06:45:44.359Z","updated_at":"2025-04-14T05:31:33.758Z","avatar_url":"https://github.com/seancribbs.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Datalog\n\nA toy implementation of naive-evaluated Datalog in Elixir, based on the blog\npost [The Essence of\nDatalog](https://dodisturb.me/posts/2018-12-25-The-Essence-of-Datalog.html). The\nDatalog program given in the blog post is included in the `Datalog.Example`\nmodule.\n\n**DO NOT USE THIS IN PRODUCTION, THIS IS FOR EDUCATIONAL PURPOSES ONLY.**\n\n## Some differences from the Haskell version\n\n* *No abstract types.* I use structs for `Rule` (`%Datalog.Rule{}`) and `Atom`\n  (`%Datalog.Atom{}`), and two-tuples for the two variants of `Term`: `Var` and\n  `Sym`.\n\n* *No monadic do-notation.* In a few places, I had to unpack the implicit\n  iteration and flat-mapping that do-notation induces and make it explicit. The\n  code looks a little strange as a result, with some `++` and `Enum.concat/1` to\n  get the desired level of list-nesting. See `eval_atom/3` for an example of\n  this.\n\n* *No inline named-functions.* When the blog author uses Haskell `where` clauses\n  to define local functions inside a function scope, I've substituted `for`\n  comprehensions or functions of the same name but different arities. Example:\n  `unify/2` takes two atoms, and `unify/1` (local function `go` in the blog\n  post) works over the zipped list of terms to unify from the inputs of\n  `unify/2`.\n\n* *No free-to-use fixpoint combinator.* I have to tail-recurse, comparing the\n  inputs to the outputs for equality. See `solve/1`.\n\n* *Pretty-printed data-structures.* I wanted the `inspect` output to look like a\n  Datalog program, so I implemented the `Inspect` protocol for the included\n  structs.\n\n## Executing the example\n\n```shell\n$ iex -S mix\nErlang/OTP 22 [erts-10.7.2.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]\n\nInteractive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)\niex(1)\u003e Datalog.Example.ancestor\n[\n  adviser(\"Andrew Rice\", \"Mistral Contrastin\").,\n  adviser(\"Dominic Orchard\", \"Mistral Contrastin\").,\n  adviser(\"Andy Hopper\", \"Andrew Rice\").,\n  adviser(\"Alan Mycroft\", \"Dominic Orchard\").,\n  adviser(\"David Wheeler\", \"Andy Hopper\").,\n  adviser(\"Rod Burstall\", \"Alan Mycroft\").,\n  adviser(\"Robin Milner\", \"Alan Mycroft\").,\n  academicAncestor(X, Y) :- adviser(X, Y).,\n  academicAncestor(X, Z) :- adviser(X, Y), academicAncestor(Y, Z).,\n  query1(Intermediate) :-\n    academicAncestor(\"Robin Milner\", Intermediate),\n    academicAncestor(Intermediate, \"Mistral Contrastin\")\n  .,\n  query2() :- academicAncestor(\"Alan Turing\", \"Mistral Contrastin\").,\n  query3() :- academicAncestor(\"David Wheeler\", \"Mistral Contrastin\").\n]\niex(2)\u003e Datalog.solve(v(1))\n[\n  adviser(\"Andrew Rice\", \"Mistral Contrastin\"),\n  adviser(\"Dominic Orchard\", \"Mistral Contrastin\"),\n  adviser(\"Andy Hopper\", \"Andrew Rice\"),\n  adviser(\"Alan Mycroft\", \"Dominic Orchard\"),\n  adviser(\"David Wheeler\", \"Andy Hopper\"),\n  adviser(\"Rod Burstall\", \"Alan Mycroft\"),\n  adviser(\"Robin Milner\", \"Alan Mycroft\"),\n  academicAncestor(\"Andrew Rice\", \"Mistral Contrastin\"),\n  academicAncestor(\"Dominic Orchard\", \"Mistral Contrastin\"),\n  academicAncestor(\"Andy Hopper\", \"Andrew Rice\"),\n  academicAncestor(\"Alan Mycroft\", \"Dominic Orchard\"),\n  academicAncestor(\"David Wheeler\", \"Andy Hopper\"),\n  academicAncestor(\"Rod Burstall\", \"Alan Mycroft\"),\n  academicAncestor(\"Robin Milner\", \"Alan Mycroft\"),\n  academicAncestor(\"Andy Hopper\", \"Mistral Contrastin\"),\n  academicAncestor(\"Alan Mycroft\", \"Mistral Contrastin\"),\n  academicAncestor(\"David Wheeler\", \"Andrew Rice\"),\n  academicAncestor(\"Rod Burstall\", \"Dominic Orchard\"),\n  academicAncestor(\"Robin Milner\", \"Dominic Orchard\"),\n  academicAncestor(\"David Wheeler\", \"Mistral Contrastin\"),\n  academicAncestor(\"Rod Burstall\", \"Mistral Contrastin\"),\n  academicAncestor(\"Robin Milner\", \"Mistral Contrastin\"),\n  query1(\"Dominic Orchard\"),\n  query1(\"Alan Mycroft\"),\n  query3()\n]\niex(3)\u003e Datalog.query(\"query1\", v(1))\n[\n  [{{:var, \"Intermediate\"}, {:sym, \"Dominic Orchard\"}}],\n  [{{:var, \"Intermediate\"}, {:sym, \"Alan Mycroft\"}}]\n]\niex(4)\u003e Datalog.query(\"query2\", v(1))\n[]\niex(5)\u003e Datalog.query(\"query3\", v(1))\n[[]]\niex(6)\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseancribbs%2Fdatalog-elixir","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseancribbs%2Fdatalog-elixir","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseancribbs%2Fdatalog-elixir/lists"}