{"id":15010374,"url":"https://github.com/smucclaw/l4-lp","last_synced_at":"2025-12-27T21:03:12.772Z","repository":{"id":224552695,"uuid":"763337255","full_name":"smucclaw/l4-lp","owner":"smucclaw","description":"Fully in-browser IDE and rule engine for L4 (a DSL for business rules), along with various language binding libraries","archived":false,"fork":false,"pushed_at":"2025-12-14T08:48:50.000Z","size":1667,"stargazers_count":8,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-12-16T12:36:33.177Z","etag":null,"topics":["clojure","clojurescript","dsl","prolog","python","swi-prolog","term-rewriting","wasm"],"latest_commit_sha":null,"homepage":"https://smucclaw.github.io/l4-lp/","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smucclaw.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-02-26T05:17:17.000Z","updated_at":"2025-12-14T08:48:51.000Z","dependencies_parsed_at":"2024-03-02T04:25:17.723Z","dependency_job_id":"28a5af5f-c9ef-4b76-9cec-3e33971dd3df","html_url":"https://github.com/smucclaw/l4-lp","commit_stats":null,"previous_names":["smucclaw/swipl-wasm-engine","smucclaw/l4-swipl-wasm","smucclaw/l4-lp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/smucclaw/l4-lp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smucclaw%2Fl4-lp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smucclaw%2Fl4-lp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smucclaw%2Fl4-lp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smucclaw%2Fl4-lp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smucclaw","download_url":"https://codeload.github.com/smucclaw/l4-lp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smucclaw%2Fl4-lp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28085173,"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","status":"online","status_checked_at":"2025-12-27T02:00:05.897Z","response_time":58,"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":["clojure","clojurescript","dsl","prolog","python","swi-prolog","term-rewriting","wasm"],"created_at":"2024-09-24T19:33:44.823Z","updated_at":"2025-12-27T21:03:12.765Z","avatar_url":"https://github.com/smucclaw.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# l4-lp (L4 Logic Program) overview\n\nThis project formalises a semantics for L4, a DSL for business rules, and\nimplements a rule engine execution pipeline, along with various language\nbinding libraries for interacting with L4 and the pipeline.\nAmong these is a browser JS ESM library which is used to implement an\nIDE that parses, transpiles and executes L4, as well as visualise execution\ntraces _completely in the browser_.\n\nTry out our IDE and rule engine [here](https://smucclaw.github.io/l4-lp/)!\n\nFor context, this evolved from an older pipeline involving\n[logical-english-client](https://github.com/smucclaw/logical-english-client)\nwhich utilised [Logical English](https://github.com/smucclaw/LogicalEnglish)\nto transpile L4 to Prolog and generate execution traces.\n\nMore precisely, this project contains:\n- A denotational semantics for L4 constitutive rules,\n  formalised as an equational theory\n  mapping L4 rules into Horn clauses in the Prolog term algebra\n  (ie. Prolog's concrete syntax),\n  implemented as a parser and transpiler in Clojure / Clojurescript.\n  \n  Note that we use such Horn clauses as our intermediate representation\n  because for one, they are syntactically close to L4, and are convenient to\n  work with.\n  Moreover, Prolog / Datalog Horn clauses have well-understood\n  semantics, and are widely adopted as the standard format for\n  (and hence highly interoperable with) many rule engines and static analysis \n  tools\n  (including SMT based solvers like\n  [Z3](https://microsoft.github.io/z3guide/docs/fixedpoints/intro/)).\n  See [this section](#denotational-semantics-and-accompanying-parser-and-transpiler)\n  for more details.\n\n- A SWI-Prolog based rule engine runtime, accompanied by\n  [custom Prolog predicates](public/resources/swipl/prelude.pl)\n  for executing transpiled L4 specifications, and obtaining execution traces.\n\n  Note that SWI-Prolog was chosen for convenience\n  (details on why that is [here](#swi-prolog-based-rule-engine-runtime)),\n  and that one can easily build a runtime for our Prolog intermediate\n  representation using Z3 for instance.\n  Currently, integrating other such backends is planned but not worked on yet.\n\n- Language binding libraries that allow other languages to interact with L4 and\n  its execution pipeline:\n  | Language | Library status | Example usage |\n  | -------- | ------ | ------------- |\n  | Clojure / JVM | In progress | [JVM main.clj](src/l4_lp/main.clj) |\n  | Clojurescript / ESM in browser | :heavy_check_mark: | [index.js](public/index.js) |\n  | Clojurescript / CommonJS on NodeJS | :heavy_check_mark: | [node_example_usage.js](public/node_example_usage.js) |\n  | Python | :heavy_check_mark: | [example_usage.py](src/l4_lp_py/example_usage.py) |\n\n  Note that all these bind to the same Clojure + SWI-Prolog code base under the\n  hood so that they have the _exact same_ functionality, behaviour and\n  semantics.\n  See [here](_) for more details.\n\n- An in-browser IDE powered by [CodeMirror](https://codemirror.net/)\n  and the browser ESM library to parse, transpile, execute L4 and visualise\n  execution traces (via [guifier](https://github.com/maliknajjar/guifier))\n  completely in the browser.\n\nSee [this section](#details-and-discussion) for more details about the\nsemantics and pipeline implemented in this project.\n\n# Dependencies\n\n- Java\n- [Clojure](https://clojure.org/guides/install_clojure)\n- [Babashka](https://github.com/babashka/babashka)\n- [proto](https://moonrepo.dev/proto)\n- [SWI-Prolog](https://www.swi-prolog.org/)\n\n# Usage\n## Setup\n```shell\n  # Install pinned version of bun in .prototools via proto\n  proto install\n\n  # Install npm dependencies.\n  proto run bun -- install\n\n  # Install SWI-Prolog runtime dependencies.\n  proto run bun -- install:swipl-deps\n\n  # Pre-compile our SWI-Prolog runtime library to qlf files.\n  proto run bun -- build:swipl-qlfs\n```\n\n## Running the web IDE demo\n- Make sure to [setup](#setup) the project first.\n- Run the following command to start a local dev server in the `public` directory:\n\n  ```shell\n    proto run bun -- start\n  ```\n\n- Navigate to \u003chttp://localhost:8000\u003e in your browser.\n\n  The webpage contains some instructions on how to use the IDE.\n\n## Compiling optimised versions of the language binding libraries and web IDE\n\nRun the following command:\n\n```shell\n  proto run bun -- build:all\n```\n\n# Details and discussion\n## Denotational semantics and accompanying parser and transpiler\n\nL4's denotational semantics is given as an equational theory from\nthe term algebra (ie concrete syntax) of L4 to that of Prolog.\nThis is primarily documented and implemented by the\n`l4-rule-\u003eprolog-rule` function in\n[l4_to_prolog.cljc](src/l4_lp/syntax/l4_to_prolog.cljc).\n\n### Points to note\n\n1. We use\n   [Meander](https://github.com/noprompt/meander)\n   to implement a term rewriting system which orients the equational theory\n   from left to right.\n\n   Each rewrite rule has an accompanying comment above it which describes\n   the equation it implements.\n\n1. We rewrite L4's concrete syntax directly into that of Prolog,\n   so that Prolog's concrete syntax is essentially our intermediate\n   representation.\n   We _do not_ have any fancy data types or separate form of abstract\n   syntax in our transpilation pipeline.\n\n2. Prolog syntax makes for an extremely convenient intermediate representation\n   to work with because:\n   1. The concrete syntax of L4's constitutive rules is a variation of\n      Prolog-style Horn clauses, containing additional syntactic sugar.\n\n   2. Prolog is homoiconic, with a concrete syntax that is very close to\n      s-expressions.\n\n   3. The transpiler and most of the rest of the project is implemented in\n      Clojure / Clojurescript which is a lisp, and hence convenient for\n      manipulating s-expressions.\n\n   4. As mentioned in the [overview](#l4-lp-overview),\n      such an intermediate representation is a rather standard one adopted by\n      many other downstream formalisms and tools that are\n      based on Horn clauses.\n      These tools utilise relatively similar semantics\n      (which as mentioned, are well-understood),\n      and can readily consume our intermediate representation.\n\n      They include:\n      - Prolog engines, like\n        [SWI](https://www.swi-prolog.org/),\n        [Ciao](https://ciao-lang.org/)\n        and\n        [Scryer](https://www.scryer.pl/).\n\n      - Datalog, like\n        [Souffle](https://souffle-lang.github.io/index.html)\n        (popular tool for static analysis)\n        and\n        [Nemo](https://github.com/knowsys/nemo)\n        (high performance rule engine which can run in the browser)\n  \n      - ASP, like\n        [sCASP](https://github.com/SWI-Prolog/sCASP)\n        and\n        [Clingo](https://github.com/potassco/clingo)\n        (these are good for counterfactual explanations and abduction)\n  \n      - SMT-based Constrained Horn Clause (CHC) solvers, like\n        [Z3](https://microsoft.github.io/z3guide/docs/fixedpoints/intro/)\n        and\n        [Eldarica](https://github.com/uuverifiers/eldarica)\n\n    In other words, adopting Prolog syntax as our intermediate representation\n    keeps our parser and transpiler really lean (ie. under 300 lines of code),\n    and also\n    allows us to equip L4 with standard, well-understood Horn clause based\n    semantics, and\n    facilitates the integration of a wide variety of tools and their\n    functionality (which we hope to achieve eventually).\n\n3. We transform nested function applications into predicative syntax, eg:\n   ```\n   MIN (SUM 0 1 (PRODUCT 1 2)) 3 \u003c MINUS 2 1\n   ```\n   gets expanded to something like:\n   ```\n   product_list([1, 2], Var__0),\n   sum_list(([0, 1, Var__0]), Var__1),\n   min_list(([Var__1, 3]), Var__2),\n   minus_list(([2, 1]), Var__3),\n   lt(Var__2, Var__3)\n   ```\n  \n   The idea is that during the recursive transformation of a term,\n   whenever we find a nested function application, we:\n   1. Capture its context in a continuation.\n   2. Generate a fresh variable of the form `Var__N`.\n   3. Throw the fresh variable to the continuation.\n   4. Lift the function application from its nested context up to the top\n      most term.\n   5. Convert the function application into a predicate application, using\n      the fresh variable as the output variable.\n    \n   Note that such rules are:\n   - Formalised with the help of a standard big-step semantics with first-class \n     continuations.\n   - Implemented using Meander's\n     [$ macro](https://cljdoc.org/d/meander/epsilon/0.0.626/doc/operator-overview#subtree-search-)\n     to conveniently manipulate nested terms and their contexts (captured as\n     continuations).\n\nCheck out the implementation and comments in the code for more details!\n\n## SWI-Prolog based rule engine runtime\nWe implement a rule engine runtime in SWI-Prolog,\nalong with some custom Prolog predicates,\nin order to execute L4 specifications that have been transpiled to our\nintermediate representation, ie the concrete syntax of Prolog.\n\nAs mentioned [previously](#l4-lp-overview),\nwe could have built a runtime\nusing any other Horn clause based formalism,\nbut for now, we chose Prolog, and SWI-Prolog in particular, as it is\nextremely convenient for the following reasons:\n\n1. Prolog is a backward-chaining rule engine for Horn clauses\n   (or at least it can be used as one, because it uses SLD-resolution),\n   and has powerful meta-programming functionality.\n\n   This means that to implement a backward chaining rule engine in Prolog\n   with custom behaviour,\n   one can simply utilise meta-programming to customise the existing behaviour\n   of the Prolog interpreter to suit their needs, rather than have to implement\n   everything like the backward chaining and unification mechanism themselves.\n\n   For instance, we can easily implement\n   [meta-predicates](https://github.com/smucclaw/l4-lp/blob/aba0a7c15fe9b2e57fc9992a97c73f9dbea48b98/public/resources/swipl/prelude.pl#L40)\n   that utilise SWI-Prolog's meta-programming APIs to hook into the Prolog interpreter\n   and log execution traces.\n   This can also be used to pass callbacks into the interpreter for an\n   interactive Q\u0026A expert system.\n   Without meta-programming, we would have to implement a whole new interpreter\n   ourselves just to get such functionality.\n\n2. SWI-Prolog has good library support, including constraint solving and\n   date libraries.\n   \n   This lets us easily solve planning problems on top of just executing\n   programs, and integrate date logic reasoning.\n\n3. SWI-Prolog has language bindings to various languages like\n   JS (including browser JS via WASM), Python and Java.\n\n   This lets us, without much additional effort, recycle the same\n   codebase and runtime to implement JS, Python and Java libraries that\n   integrate L4 with them, and even execute in the browser.\n   In addition, this ensures that the execution behaviour and semantics across\n   all these libraries is exactly the same.\n\n## Language binding libraries for L4\nWe provide libraries for Clojure, Java, JS and Python with language bindings\nto L4, which expose programmatic APIs for these languages to interop with\nL4 and call various\nparts of the\nClojure parser \u0026rarr;\nClojure transpiler \u0026rarr;\nSWI Prolog rule engine\npipeline, and interop with L4.\n\nThis is easy because:\n- Our parser and transpiler are written entirely in Clojure, which compiles to\n  and interops bidirectionally with _both_ JVM bytecode and JS.\n  \n  This means that just by writing our parser \u0026rarr; transpiler pipeline in\n  Clojure, we get to integrate it with Java and JS for free.\n\n- [JsPyBridge](https://github.com/extremeheat/JSPyBridge)\n  offers almost seamless bidirectional interop between JS and Python.\n\n  This lets us integrate our Clojure parser \u0026rarr; Clojure transpiler with\n  Python as well, for free, because we can interop\n  Clojure \u0026harr; JS \u0026harr; Python\n\n- SWI-Prolog has good bindings and bidirectional interop with\n  [JS via WASM](https://github.com/SWI-Prolog/npm-swipl-wasm),\n  [Python](https://github.com/SWI-Prolog/packages-swipy)\n  and\n  [Java](https://jpl7.org/).\n\n  Using this, we wrote some glue code in Clojure and Python to connect the\n  output of the Clojure transpiler to the SWI Prolog rule engine\n  to complete the whole pipeline.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmucclaw%2Fl4-lp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmucclaw%2Fl4-lp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmucclaw%2Fl4-lp/lists"}