{"id":15540251,"url":"https://github.com/rm-hull/wam","last_synced_at":"2025-04-23T16:43:52.872Z","repository":{"id":31361414,"uuid":"34924307","full_name":"rm-hull/wam","owner":"rm-hull","description":"Gradual WAM implementation using Hassan Aït-Kaci's tutorial reconstruction","archived":false,"fork":false,"pushed_at":"2018-10-06T11:20:27.000Z","size":151,"stargazers_count":26,"open_issues_count":1,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-10-03T12:17:34.082Z","etag":null,"topics":["clojure","parser-combinators","prolog-implementation","tutorial","unification","wam"],"latest_commit_sha":null,"homepage":"http://www.destructuring-bind.org/wam/","language":"Clojure","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/rm-hull.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-01T21:14:44.000Z","updated_at":"2024-09-12T15:13:18.000Z","dependencies_parsed_at":"2022-08-24T14:21:39.266Z","dependency_job_id":null,"html_url":"https://github.com/rm-hull/wam","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Fwam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Fwam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Fwam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Fwam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rm-hull","download_url":"https://codeload.github.com/rm-hull/wam/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250472237,"owners_count":21436105,"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":["clojure","parser-combinators","prolog-implementation","tutorial","unification","wam"],"created_at":"2024-10-02T12:13:21.626Z","updated_at":"2025-04-23T16:43:52.858Z","avatar_url":"https://github.com/rm-hull.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Warren's Abstract Machine\n\n[![Build Status](https://travis-ci.org/rm-hull/wam.svg?branch=master)](http://travis-ci.org/rm-hull/wam)\n[![Coverage Status](https://coveralls.io/repos/github/rm-hull/wam/badge.svg?branch=master)](https://coveralls.io/github/rm-hull/wam?branch=master)\n[![Dependencies Status](https://versions.deps.co/rm-hull/wam/status.svg)](https://versions.deps.co/rm-hull/wam)\n[![Maintenance](https://img.shields.io/maintenance/yes/2018.svg?maxAge=2592000)]()\n\nA gradual WAM implementation in Clojure following Hassan Aït-Kaci's tutorial reconstruction.\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [Language ℒ₀ – Unification](#language-%E2%84%92%E2%82%80--unification)\n  - [Exercise 2.1 (pg. 9)](#exercise-21-pg-9)\n  - [EBNF ℒ₀ Grammar \u0026 Parser Combinators](#ebnf-%E2%84%92%E2%82%80-grammar--parser-combinators)\n  - [Compiling ℒ₀ queries](#compiling-%E2%84%92%E2%82%80-queries)\n  - [Compiling ℒ₀ programs](#compiling-%E2%84%92%E2%82%80-programs)\n  - [Exercise 2.2 (pg. 14)](#exercise-22-pg-14)\n  - [Exercise 2.3 (pg. 14)](#exercise-23-pg-14)\n  - [Exercise 2.4 (pg. 14)](#exercise-24-pg-14)\n  - [Exercise 2.5 (pg. 14)](#exercise-25-pg-14)\n- [Language ℒ₁ – Argument Registers](#language-%E2%84%92%E2%82%81--argument-registers)\n  - [Exercise 2.6 (pg. 18)](#exercise-26-pg-18)\n  - [Exercise 2.7 (pg. 18)](#exercise-27-pg-18)\n  - [Exercise 2.8 (pg. 18)](#exercise-28-pg-18)\n  - [Exercise 2.9 (pg. 19)](#exercise-29-pg-19)\n- [Language ℒ₂ – Flat Resolution](#language-%E2%84%92%E2%82%82--flat-resolution)\n- [Language ℒ₃ – Prolog](#language-%E2%84%92%E2%82%83--prolog)\n- [References](#references)\n- [License](#license)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Language ℒ₀ – Unification\n\n### Exercise 2.1 (pg. 9)\n\n\u003e Verify that the effect of executing the sequence of instructions shown in\n\u003e Figure 2.3 (starting with `H` = 0) does indeed yield a correct heap\n\u003e representation for the term _p(Z, h(Z, W), f(W))_ — the one shown earlier\n\u003e as Figure 2.1, in fact.\n\nSee [ℳ₀ machine instructions](https://github.com/rm-hull/wam/blob/L0/src/wam/instruction_set.clj) for implementation details\n\n```clojure\n  (use 'wam.instruction-set)\n  (use 'wam.store)\n  (use 'table.core)\n\n  (def context (make-context))\n\n  (-\u003e\n    context\n    (put-structure 'h|2, 'X3)\n    (set-variable 'X2)\n    (set-variable 'X5)\n    (put-structure 'f|1, 'X4)\n    (set-value 'X5)\n    (put-structure 'p|3, 'X1)\n    (set-value 'X2)\n    (set-value 'X3)\n    (set-value 'X4)\n    heap\n    (table :style :unicode))\n```\nProduces:\n```\n┌──────┬────────────┐\n│ key  │ value      │\n├──────┼────────────┤\n│ 1000 ╎ [STR 1001] │\n│ 1001 ╎ h|2        │\n│ 1002 ╎ [REF 1002] │\n│ 1003 ╎ [REF 1003] │\n│ 1004 ╎ [STR 1005] │\n│ 1005 ╎ f|1        │\n│ 1006 ╎ [REF 1003] │\n│ 1007 ╎ [STR 1008] │\n│ 1008 ╎ p|3        │\n│ 1009 ╎ [REF 1002] │\n│ 1010 ╎ [STR 1001] │\n│ 1011 ╎ [STR 1005] │\n└──────┴────────────┘\n```\n\n### EBNF ℒ₀ Grammar \u0026 Parser Combinators\n\nThe simplistic EBNF [grammar rules](https://github.com/rm-hull/wam/blob/master/src/wam/grammar.clj)\nfor ℒ₀ below have been implemented using a [parser monad](https://github.com/rm-hull/jasentaa).\n\n* _**\u0026lt;Digit\u0026gt;** ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'_\n\n* _**\u0026lt;Number\u0026gt;** ::= \u0026lt;Digit\u0026gt; \u0026lt;Digit\u0026gt;*_\n\n* _**\u0026lt;LowerAlpha\u0026gt;** ::= 'a' .. 'z'_\n\n* _**\u0026lt;UpperAlpha\u0026gt;** ::= 'A' .. 'Z'_\n\n* _**\u0026lt;AlphaNum\u0026gt;** ::= \u0026lt;LowerAlpha\u0026gt; | \u0026lt;UpperAlpha\u0026gt; | \u0026lt;Digit\u0026gt;_\n\n* _**\u0026lt;Predicate\u0026gt;** ::= \u0026lt;LowerAlpha\u0026gt; \u0026lt;AlphaNum\u0026gt;*_\n\n* _**\u0026lt;Constant\u0026gt;** ::= \u0026lt;Number\u0026gt;_\n\n* _**\u0026lt;Variable\u0026gt;** ::= \u0026lt;UpperAlpha\u0026gt; \u0026lt;AlphaNum\u0026gt;* |_ '_'\n\n* _**\u0026lt;Structure\u0026gt;** ::= \u0026lt;Predicate\u0026gt; | \u0026lt;Predicate\u0026gt; '(' \u0026lt;List\u0026gt; ')'_\n\n* _**\u0026lt;List\u0026gt;** ::= \u0026lt;Element\u0026gt; | \u0026lt;Element\u0026gt; ',' \u0026lt;List\u0026gt;_\n\n* _**\u0026lt;Element\u0026gt;** ::= \u0026lt;Variable\u0026gt; | \u0026lt;Constant\u0026gt; | \u0026lt;Structure\u0026gt;_\n\nParsing the term _p(Z, h(Z, W), f(W))_ with:\n\n```clojure\n(use 'wam.grammar)\n(use 'jasentaa.parser)\n(parse-all structure \"p(Z, h(Z, W), f(W))\")\n```\nyields a structure as follows:\n```\n#Structure{:functor p|3,\n           :args (#Variable{:name Z}\n                  #Structure{:functor h|2,\n                             :args (#Variable{:name Z}\n                                    #Variable{:name W}})}\n                  #Structure{:functor f|1,\n                             :args (#Variable{:name W})})}\n```\n### Compiling ℒ₀ queries\n\nNow that the term _p(Z, h(Z, W), f(W))_ parses into a hierarchical data\nstructure, a breadth-first search is employed to allocate registers on a\nleast available index basis:\n\n```clojure\n(use 'wam.compiler)\n(use 'wam.grammar)\n(use 'jasentaa.parser)\n(use 'table.core)\n\n(def term (parse-all structure \"p(Z, h(Z, W), f(W))\"))\n(table (register-allocation term) :style :unicode)\n```\nevaluates as:\n```\n┌──────────────────┬───────┐\n│ key              │ value │\n├──────────────────┼───────┤\n│ p(Z h(Z W) f(W)) ╎ X1    │\n│ Z                ╎ X2    │\n│ h(Z W)           ╎ X3    │\n│ f(W)             ╎ X4    │\n│ W                ╎ X5    │\n└──────────────────┴───────┘\n```\nInspecting the structures, and indeed it matches as follows:\n\n* X1 = p(X2, X3, X4)\n* X2 = Z\n* X3 = h(X2, X5)\n* X4 = f(X5)\n* X5 = W\n\nNext, given that we have a linear register allocation, walking\nthe query term structures in depth-first post-order means that\ninstructions can be assembled as follows:\n\n```clojure\n(use 'wam.compiler)\n(use 'wam.grammar)\n(use 'table.core)\n\n(table\n  (cons\n    [\"instr\" \"arg1\" \"arg2\"]\n    (emit-instructions query-builder term (register-allocation term)))\n  :style :unicode)\n```\n\nWhich returns a list of instructions, which corresponds to Figure 2.3\nin the tutorial:\n```\n┌──────────────────────────────────────────────┬──────┬──────┐\n│ instr                                        │ arg1 │ arg2 │\n├──────────────────────────────────────────────┼──────┼──────┤\n│ #function[wam.instruction-set/put-structure] ╎ h|2  ╎ X3   │\n│ #function[wam.instruction-set/set-variable]  ╎ X2   ╎      │\n│ #function[wam.instruction-set/set-variable]  ╎ X5   ╎      │\n│ #function[wam.instruction-set/put-structure] ╎ f|1  ╎ X4   │\n│ #function[wam.instruction-set/set-value]     ╎ X5   ╎      │\n│ #function[wam.instruction-set/put-structure] ╎ p|3  ╎ X1   │\n│ #function[wam.instruction-set/set-value]     ╎ X2   ╎      │\n│ #function[wam.instruction-set/set-value]     ╎ X3   ╎      │\n│ #function[wam.instruction-set/set-value]     ╎ X4   ╎      │\n└──────────────────────────────────────────────┴──────┴──────┘\n```\nThe instructions are not directly executable as yet, as a context\nmust be supplied in the first argument to each instruction, but\nthey are however in a suitable format for returning a function\nthat can execute them given a context:\n\n```clojure\n(use 'wam.compiler)\n(use 'wam.grammar)\n(use 'wam.store)\n(use 'table.core)\n\n(def context (make-context))\n\n(def query0\n  (-\u003e\u003e\n    \"p(Z, h(Z, W), f(W))\"\n    (parse-all structure)\n    (compile-term query-builder)))\n\n(-\u003e context query0 heap table)\n```\nThis produces the same heap representation as earlier, but significantly, was\ninstead generated automatically from executing emitted WAM instructions,\nwhich were derived from hierarchical data structures, which in turn were\nparsed from a string representation **\"p(Z, h(Z, W), f(W))\"**.\n```\n┌──────┬────────────┐\n│ key  │ value      │\n├──────┼────────────┤\n│ 1000 ╎ [STR 1001] │\n│ 1001 ╎ h|2        │\n│ 1002 ╎ [REF 1002] │\n│ 1003 ╎ [REF 1003] │\n│ 1004 ╎ [STR 1005] │\n│ 1005 ╎ f|1        │\n│ 1006 ╎ [REF 1003] │\n│ 1007 ╎ [STR 1008] │\n│ 1008 ╎ p|3        │\n│ 1009 ╎ [REF 1002] │\n│ 1010 ╎ [STR 1001] │\n│ 1011 ╎ [STR 1005] │\n└──────┴────────────┘\n```\n### Compiling ℒ₀ programs\n\nCompiling a program term follows a similar vein to query term construction:\nregisters are allocated breadth-first, but instead of walking the tree in\npost-order, a program is walked in pre-order. The rules for emitting instructions\nare also subtly different. Assuming the same helper methods as before:\n\n```clojure\n(use 'wam.compiler)\n(use 'wam.grammar)\n(use 'table.core)\n\n; Assume the same helper functions as before\n\n(def term (parse-all structure \"p(f(X), h(Y, f(a)), Y)\"))\n\n(table\n  (cons\n    [\"instr\" \"arg1\" \"arg2\"]\n    (emit-instructions program-builder term (register-allocation term)))\n  :style :unicode)\n\n```\nWhich returns a list of instructions, which corresponds to Figure 2.4\nin the tutorial:\n```\n┌───────────────────────────────────────────────┬──────┬──────┐\n│ instr                                         │ arg1 │ arg2 │\n├───────────────────────────────────────────────┼──────┼──────┤\n│ #function[wam.instruction-set/get-structure]  ╎ p|3  ╎ X1   │\n│ #function[wam.instruction-set/unify-variable] ╎ X2   ╎      │\n│ #function[wam.instruction-set/unify-variable] ╎ X3   ╎      │\n│ #function[wam.instruction-set/unify-variable] ╎ X4   ╎      │\n│ #function[wam.instruction-set/get-structure]  ╎ f|1  ╎ X2   │\n│ #function[wam.instruction-set/unify-variable] ╎ X5   ╎      │\n│ #function[wam.instruction-set/get-structure]  ╎ h|2  ╎ X3   │\n│ #function[wam.instruction-set/unify-value]    ╎ X4   ╎      │\n│ #function[wam.instruction-set/unify-variable] ╎ X6   ╎      │\n│ #function[wam.instruction-set/get-structure]  ╎ f|1  ╎ X6   │\n│ #function[wam.instruction-set/unify-variable] ╎ X7   ╎      │\n│ #function[wam.instruction-set/get-structure]  ╎ a|0  ╎ X7   │\n└───────────────────────────────────────────────┴──────┴──────┘\n```\n### Exercise 2.2 (pg. 14)\n\n\u003e Give heap representations for the terms _f(X, g(X, a))_ and _f(b, Y)_.\n\u003e Let _a\u003csub\u003e1\u003c/sub\u003e_ and _a\u003csub\u003e2\u003c/sub\u003e_ be their respective heap addresses,\n\u003e and let _a\u003csub\u003ex\u003c/sub\u003e_ and _a\u003csub\u003ey\u003c/sub\u003e_ be the heap addresses\n\u003e corresponding to variables _X_ and _Y_, respectively. Trace the effects of\n\u003e executing _unify(a\u003csub\u003e1\u003c/sub\u003e, a\u003csub\u003e2\u003c/sub\u003e)_, verifying that it terminates\n\u003e with the eventual dereferenced bindings from _a\u003csub\u003ex\u003c/sub\u003e_ and\n\u003e _a\u003csub\u003ey\u003c/sub\u003e_ corresponding to _X = b_ and _Y = g(b, a)_.\n\nBy applying the query terms to an empty context,\n\n```clojure\n(use 'wam.compiler)\n(use 'wam.store)\n(use 'table.core)\n\n(-\u003e\n  (make-context)\n  (query \"f(X, g(X, a))\")\n  (query \"f(b, Y)\")\n  diag)\n```\nGives the following heap structure. Note that the heap addresses for\n_a\u003csub\u003e1\u003c/sub\u003e_, _a\u003csub\u003e2\u003c/sub\u003e_, _a\u003csub\u003ex\u003c/sub\u003e_ and _a\u003csub\u003ey\u003c/sub\u003e_\nhave been annotated at locations 1006, 1012, 1008 and 1015 respectively.\n```\nHeap                   Registers             Variables\n------------------------------------------------------------\n┌──────┬────────────┐  ┌─────┬────────────┐  ┌─────┬───────┐\n│ key  │ value      │  │ key │ value      │  │ key │ value │\n├──────┼────────────┤  ├─────┼────────────┤  ├─────┼───────┤\n│ 1000 ╎ [STR 1001] │  │ X1  ╎ [STR 1013] │  │ X   ╎ X2    │\n│ 1001 ╎ a|0        │  │ X2  ╎ [STR 1011] │  │ Y   ╎ X3    │\n│ 1002 ╎ [STR 1003] │  │ X3  ╎ [REF 1015] │  └─────┴───────┘\n│ 1003 ╎ g|2        │  │ X4  ╎ [STR 1001] │\n│ 1004 ╎ [REF 1004] │  └─────┴────────────┘\n│ 1005 ╎ [STR 1001] │\n│ 1006 ╎ [STR 1007] │    ← a1\n│ 1007 ╎ f|2        │\n│ 1008 ╎ [REF 1004] │    ← aX\n│ 1009 ╎ [STR 1003] │\n│ 1010 ╎ [STR 1011] │\n│ 1011 ╎ b|0        │\n│ 1012 ╎ [STR 1013] │    ← a2\n│ 1013 ╎ f|2        │\n│ 1014 ╎ [STR 1011] │\n│ 1015 ╎ [REF 1015] │    ← aY\n└──────┴────────────┘\n```\nNow, calling _unify(a\u003csub\u003e1\u003c/sub\u003e, a\u003csub\u003e2\u003c/sub\u003e)_, the changed context store\nis displayed below.\n\n```clojure\n(use 'wam.anciliary)\n\n(defn tee [v func]\n  (func v)\n  v)\n\n(-\u003e\n  (make-context)\n  (query \"f(X, g(X, a))\")\n  (query \"f(b, Y)\")\n  (unify 1012 1006)\n  diag\n  (tee #(println \"X =\" (resolve-struct % (register-address 'X2))))\n  (tee #(println \"Y =\" (resolve-struct % (register-address 'X3)))))\n```\nNote that the context failed flag returns as false (not shown), indicating\nunification was successful.\n```\nHeap                   Registers             Variables\n------------------------------------------------------------\n┌──────┬────────────┐  ┌─────┬────────────┐  ┌─────┬───────┐\n│ key  │ value      │  │ key │ value      │  │ key │ value │\n├──────┼────────────┤  ├─────┼────────────┤  ├─────┼───────┤\n│ 1000 ╎ [STR 1001] │  │ X1  ╎ [STR 1013] │  │ X   ╎ X2    │\n│ 1001 ╎ a|0        │  │ X2  ╎ [STR 1011] │  │ Y   ╎ X3    │\n│ 1002 ╎ [STR 1003] │  │ X3  ╎ [REF 1015] │  └─────┴───────┘\n│ 1003 ╎ g|2        │  │ X4  ╎ [STR 1001] │\n│ 1004 ╎ [STR 1011] │  └─────┴────────────┘\n│ 1005 ╎ [STR 1001] │\n│ 1006 ╎ [STR 1007] │\n│ 1007 ╎ f|2        │\n│ 1008 ╎ [REF 1004] │\n│ 1009 ╎ [STR 1003] │\n│ 1010 ╎ [STR 1011] │\n│ 1011 ╎ b|0        │\n│ 1012 ╎ [STR 1013] │\n│ 1013 ╎ f|2        │\n│ 1014 ╎ [STR 1011] │\n│ 1015 ╎ [STR 1003] │\n└──────┴────────────┘\n\nX = b\nY = g(b, a)\n```\nInspecting the heap, and it becomes clear that:\n\n* dereferencing _a\u003csub\u003ex\u003c/sub\u003e_, `STR 1011` → `b|0`, so _X = b_\n* dereferencing _a\u003csub\u003ey\u003c/sub\u003e_, `STR 1015` → `STR 1003` → `g|2`, so _Y = g(X, a) = g(b, a)_\n\n### Exercise 2.3 (pg. 14)\n\n\u003e Verify that the effect of executing the sequence of instructions shown in\n\u003e Figure 2.4 right after that in Figure 2.3 produces the MGU of the terms\n\u003e _p(Z, h(Z, W), f(W))_ and _p(f(X), h(Y, f(a)), Y)_. That is, the\n\u003e (dereferenced) bindings corresponding to _W = f(a)_, _X = f(a)_,\n\u003e _Y = f(f(a))_, _Z = f(f(a))_.\n\n_MGU_ = Most General Unifier\n\n```clojure\n(-\u003e\n  (make-context)\n\n  ; fig 2.3: compiled code for ℒ₀ query ?- p(Z, h(Z, W), f(W)).\n  (put-structure 'h|2, 'X3)\n  (set-variable 'X2)\n  (set-variable 'X5)\n  (put-structure 'f|1, 'X4)\n  (set-value 'X5)\n  (put-structure 'p|3, 'X1)\n  (set-value 'X2)\n  (set-value 'X3)\n  (set-value 'X4)\n\n  ; fig 2.4: compiled code for ℒ₀ query ?- p(f(X), h(Y, f(a)), Y).\n  (get-structure 'p|3, 'X1)\n  (unify-variable 'X2)\n  (unify-variable 'X3)\n  (unify-variable 'X4)\n  (get-structure 'f|1, 'X2)\n  (unify-variable 'X5)\n  (get-structure 'h|2, 'X3)\n  (unify-value 'X4)\n  (unify-variable 'X6)\n  (get-structure 'f|1, 'X6)\n  (unify-variable 'X7)\n  (get-structure 'a|0, 'X7)\n\n  diag\n\n  (tee #(println \"W =\" (resolve-struct % (register-address 'X5))))\n  (tee #(println \"X =\" (resolve-struct % (register-address 'X5))))\n  (tee #(println \"Y =\" (resolve-struct % (register-address 'X4))))\n  (tee #(println \"Z =\" (resolve-struct % (register-address 'X2)))))\n```\nPrints:\n```\nHeap                   Registers             Variables\n------------------------------------------------------\n┌──────┬────────────┐  ┌─────┬────────────┐  ┌───────┐\n│ key  │ value      │  │ key │ value      │  │ value │\n├──────┼────────────┤  ├─────┼────────────┤  ├───────┤\n│ 1000 ╎ [STR 1001] │  │ X1  ╎ [STR 1008] │  └───────┘\n│ 1001 ╎ h|2        │  │ X2  ╎ [REF 1002] │\n│ 1002 ╎ [STR 1013] │  │ X3  ╎ [STR 1001] │\n│ 1003 ╎ [STR 1016] │  │ X4  ╎ [STR 1005] │\n│ 1004 ╎ [STR 1005] │  │ X5  ╎ [REF 1014] │\n│ 1005 ╎ f|1        │  │ X6  ╎ [REF 1003] │\n│ 1006 ╎ [REF 1003] │  │ X7  ╎ [REF 1017] │\n│ 1007 ╎ [STR 1008] │  └─────┴────────────┘\n│ 1008 ╎ p|3        │\n│ 1009 ╎ [REF 1002] │\n│ 1010 ╎ [STR 1001] │\n│ 1011 ╎ [STR 1005] │\n│ 1012 ╎ [STR 1013] │\n│ 1013 ╎ f|1        │\n│ 1014 ╎ [REF 1003] │\n│ 1015 ╎ [STR 1016] │\n│ 1016 ╎ f|1        │\n│ 1017 ╎ [STR 1019] │\n│ 1018 ╎ [STR 1019] │\n│ 1019 ╎ a|0        │\n└──────┴────────────┘\n\nW = f(a)\nX = f(a)\nY = f(f(a))\nZ = f(f(a))\n```\n\n### Exercise 2.4 (pg. 14)\n\n\u003e What are the respective sequences of ℳ₀ instructions for ℒ₀ _query_\n\u003e term ?-_p(f(X), h(Y, f(a)), Y)_ and _program_ term _p(Z, h(Z, W), f(W))_?\n\nSetting the execution trace to `true` and running the two terms:\n\n```clojure\n(-\u003e\n  (make-context)\n  (assoc :trace true)\n  (query \"p(Z, h(Z, W), f(W))\")\n  (program \"p(f(X), h(Y, f(a)), Y)\"))\n```\n\nGives the following instruction list:\n```\nput_structure h|2, X3\nset_variable X2\nset_variable X5\nput_structure f|1, X4\nset_value X5\nput_structure p|3, X1\nset_value X2\nset_value X3\nset_value X4\nget_structure p|3, X1\nunify_variable X2\nunify_variable X3\nunify_variable X4\nget_structure f|1, X2\nunify_variable X5\nget_structure h|2, X3\nunify_value X4\nunify_variable X6\nget_structure f|1, X6\nunify_variable X7\nget_structure a|0, X7\n```\n\n### Exercise 2.5 (pg. 14)\n\n\u003e After doing Exercise 2.4, verify that the effects of executing the sequence\n\u003e you produced yields the same solution as that of [Exercise 2.3](#exercise-23-pg-14).\n\n\nExecuting:\n\n```clojure\n(-\u003e\n  (make-context)\n  (assoc :trace true)\n  (query \"p(Z, h(Z, W), f(W))\")\n  (program \"p(f(X), h(Y, f(a)), Y)\")\n  diag\n\n  (tee #(println \"W =\" (resolve-struct % (register-address 'X5))))\n  (tee #(println \"X =\" (resolve-struct % (register-address 'X5))))\n  (tee #(println \"Y =\" (resolve-struct % (register-address 'X4))))\n  (tee #(println \"Z =\" (resolve-struct % (register-address 'X2)))))\n```\nThis gives the same output as [exercise 2.3](#exercise-23-pg-14) (albeit with extra register allocations):\n```\nHeap                   Registers             Variables\n------------------------------------------------------------\n┌──────┬────────────┐  ┌─────┬────────────┐  ┌─────┬───────┐\n│ key  │ value      │  │ key │ value      │  │ key │ value │\n├──────┼────────────┤  ├─────┼────────────┤  ├─────┼───────┤\n│ 1000 ╎ [STR 1001] │  │ X1  ╎ [STR 1008] │  │ W   ╎ X5    │\n│ 1001 ╎ h|2        │  │ X2  ╎ [REF 1002] │  │ X   ╎ X5    │\n│ 1002 ╎ [STR 1013] │  │ X3  ╎ [STR 1001] │  │ Y   ╎ X4    │\n│ 1003 ╎ [STR 1016] │  │ X4  ╎ [STR 1005] │  │ Z   ╎ X2    │\n│ 1004 ╎ [STR 1005] │  │ X5  ╎ [REF 1014] │  └─────┴───────┘\n│ 1005 ╎ f|1        │  │ X6  ╎ [REF 1003] │\n│ 1006 ╎ [REF 1003] │  │ X7  ╎ [REF 1017] │\n│ 1007 ╎ [STR 1008] │  └─────┴────────────┘\n│ 1008 ╎ p|3        │\n│ 1009 ╎ [REF 1002] │\n│ 1010 ╎ [STR 1001] │\n│ 1011 ╎ [STR 1005] │\n│ 1012 ╎ [STR 1013] │\n│ 1013 ╎ f|1        │\n│ 1014 ╎ [REF 1003] │\n│ 1015 ╎ [STR 1016] │\n│ 1016 ╎ f|1        │\n│ 1017 ╎ [STR 1019] │\n│ 1018 ╎ [STR 1019] │\n│ 1019 ╎ a|0        │\n└──────┴────────────┘\n\nW = f(a)\nX = f(a)\nY = f(f(a))\nZ = f(f(a))\n```\n\n## Language ℒ₁ – Argument Registers\n\n### Exercise 2.6 (pg. 18)\n\n\u003e Verify that the effect of executing the sequence of ℳ₁ instructions\n\u003e shown in Figure 2.9 produces the same heap representation as that produced by\n\u003e the ℳ₀ code of Figure 2.3 (see [Exercise 2.1](#exercise-21-pg-9)).\n\nAssuming the same imports and initial context as perviously:\n\n```clojure\n(-\u003e\n  (make-context)\n  (put-variable 'X4, 'A1)\n  (put-structure 'h|2, 'A2)\n  (set-value 'X4)\n  (set-variable 'X5)\n  (put-structure 'f|1, 'A3)\n  (set-value 'X5)\n  heap\n  table)\n```\ngives:\n```\n┌──────┬────────────┐\n│ key  │ value      │\n├──────┼────────────┤\n│ 1000 ╎ [REF 1000] │\n│ 1001 ╎ [STR 1002] │\n│ 1002 ╎ h|2        │\n│ 1003 ╎ [REF 1000] │\n│ 1004 ╎ [REF 1004] │\n│ 1005 ╎ [STR 1006] │\n│ 1006 ╎ f|1        │\n│ 1007 ╎ [REF 1004] │\n└──────┴────────────┘\n```\nApart from the term root, the heap is layed out _similarly_ to that of\nFigure 2.3 as below, albeit with different references:\n```\n                         ┌──────┬────────────┐\n┌──────┬────────────┐    │ key  │ value      │\n│ key  │ value      │    ├──────┼────────────┤\n├──────┼────────────┤    │ 1000 ╎ [REF 1000] │\n│ 1000 ╎ [STR 1001] │    │ 1001 ╎ [STR 1002] │\n│ 1001 ╎ h|2        │    │ 1002 ╎ h|2        │\n│ 1002 ╎ [REF 1002] │    │ 1003 ╎ [REF 1000] │\n│ 1003 ╎ [REF 1003] │    │ 1004 ╎ [REF 1004] │\n│ 1004 ╎ [STR 1005] │    │ 1005 ╎ [STR 1006] │\n│ 1005 ╎ f|1        │    │ 1006 ╎ f|1        │\n│ 1006 ╎ [REF 1003] │    │ 1007 ╎ [REF 1004] │\n│ 1007 ╎ [STR 1008] │    └──────┴────────────┘\n│ 1008 ╎ p|3        │\n│ 1009 ╎ [REF 1002] │\n│ 1010 ╎ [STR 1001] │\n│ 1011 ╎ [STR 1005] │\n└──────┴────────────┘\n\n```\n\n### Exercise 2.7 (pg. 18)\n\n\u003e Verify that the effect of executing the sequence of ℳ₁ instructions\n\u003e shown in Figure 2.10 right after that in Figure 2.9 produces the MGU of the\n\u003e terms _p(Z, h(Z, W), f(W))_ and _p(f(X), h(Y, f(a)), Y)_. That is, the binding\n\u003e _W = f(a)_, _X = f(a)_, _Y = f(f(a))_, _Z = f(f(a))_.\n\nDefining _p/3_ as:\n\n```clojure\n(def p|3\n  (list\n    [get-structure 'f|1, 'A1]\n    [unify-variable 'X4]\n    [get-structure 'h|2, 'A2]\n    [unify-variable 'X5]\n    [unify-variable 'X6]\n    [get-value 'X5, 'A3]\n    [get-structure 'f|1, 'X6]\n    [unify-variable 'X7]\n    [get-structure 'a|0, 'X7]\n    [proceed]))\n```\nThen, executing the program term directly after the query term:\n\n```clojure\n(-\u003e\n  ctx\n  (put-variable 'X4, 'A1)\n  (put-structure 'h|2, 'A2)\n  (set-value 'X4)\n  (set-variable 'X5)\n  (put-structure 'f|1, 'A3)\n  (set-value 'X5)\n  (load 'p|3 p|3)\n  (call 'p|3)\n  diag\n  (tee #(println \"W =\" (resolve-struct % (register-address 'X4))))\n  (tee #(println \"X =\" (resolve-struct % (register-address 'X4))))\n  (tee #(println \"Y =\" (resolve-struct % (register-address 'A3))))\n  (tee #(println \"Z =\" (resolve-struct % (register-address 'X5)))))\n```\n\ngives:\n\n```\nHeap                   Registers             Variables\n------------------------------------------------------\n┌──────┬────────────┐  ┌─────┬────────────┐  ┌───────┐\n│ key  │ value      │  │ key │ value      │  │ value │\n├──────┼────────────┤  ├─────┼────────────┤  ├───────┤\n│ 1000 ╎ [STR 1009] │  │ X1  ╎ [REF 1000] │  └───────┘\n│ 1001 ╎ [STR 1002] │  │ X2  ╎ [STR 1002] │\n│ 1002 ╎ h|2        │  │ X3  ╎ [STR 1006] │\n│ 1003 ╎ [REF 1000] │  │ X4  ╎ [REF 1010] │\n│ 1004 ╎ [STR 1012] │  │ X5  ╎ [REF 1000] │\n│ 1005 ╎ [STR 1006] │  │ X6  ╎ [REF 1004] │\n│ 1006 ╎ f|1        │  │ X7  ╎ [REF 1013] │\n│ 1007 ╎ [REF 1004] │  └─────┴────────────┘\n│ 1008 ╎ [STR 1009] │\n│ 1009 ╎ f|1        │\n│ 1010 ╎ [REF 1004] │\n│ 1011 ╎ [STR 1012] │\n│ 1012 ╎ f|1        │\n│ 1013 ╎ [STR 1015] │\n│ 1014 ╎ [STR 1015] │\n│ 1015 ╎ a|0        │\n└──────┴────────────┘\n\nW = f(a)\nX = f(a)\nY = f(f(a))\nZ = f(f(a))\n```\n### Exercise 2.8 (pg. 18)\n\n\u003e What are the respective sequences of ℳ₁ instructions for ℒ₁ _query_\n\u003e term ?-_p(f(X), h(Y, f(a)), y)_ and ℒ₁ _program_ term _p(Z, h(Z, W), f(W))_?\n\nThere is a bit of a leap here in the tutorial, and I'm not sure if I fully\nunderstand, but the query term ?-_p(f(X), h(Y, f(a)), y)_ is now build from\nthe following instructions:\n\n```\nput-structure f|1, A1\nset-variable X4)\nput-structure h|2, A2\nset-variable A3)\nput-structure f|1, X5\nput-structure a|0, X6\nset-value A3\ncall p|3\n```\n\nAnd the program term _p(Z, h(Z, W), f(W))_ is comprised of:\n\n```\nunify-variable A1\nget-structure h|2, A2\nunify-value A1\nunify-variable X4\nget-structure f|1, A3\nunify-value X4\nproceed\n```\n\n### Exercise 2.9 (pg. 19)\n\n\u003e After doing [Exercise 2.8](#exercise-28-pg-18), verify that the effect of executing the\n\u003e sequence you produced yields the same solution as that of [Exercise 2.7](#exercise-27-pg-18).\n\n\nExecuting the program against the query term does give the same unification\nresult as previously:\n\n```clojure\n(def p|3\n  (list\n    [unify-variable 'A1]\n    [get-structure 'h|2, 'A2]\n    [unify-value 'A1]\n    [unify-variable 'X4]\n    [get-structure 'f|1, 'A3]\n    [unify-value 'X4]\n    [proceed]))\n\n(-\u003e\n  ctx\n  (put-structure 'f|1, 'A1)\n  (set-variable 'X4)\n  (put-structure 'h|2, 'A2)\n  (set-variable 'A3)\n  (put-structure 'f|1, 'X5)\n  (put-structure 'a|0, 'X6)\n  (set-value 'A3)\n  (load 'p|3 p|3)\n  (call 'p|3)\n  (diag)\n  (tee #(println \"W =\" (resolve-struct % (register-address 'X4))))\n  (tee #(println \"X =\" (resolve-struct % (register-address 'X4))))\n  (tee #(println \"Y =\" (resolve-struct % (register-address 'A3))))\n  (tee #(println \"Z =\" (resolve-struct % (register-address 'A1)))))\n```\n\nOutputs:\n\n```\nHeap                   Registers             Variables\n------------------------------------------------------\n┌──────┬────────────┐  ┌─────┬────────────┐  ┌───────┐\n│ key  │ value      │  │ key │ value      │  │ value │\n├──────┼────────────┤  ├─────┼────────────┤  ├───────┤\n│ 1000 ╎ [STR 1001] │  │ X1  ╎ [STR 1001] │  └───────┘\n│ 1001 ╎ f|1        │  │ X2  ╎ [STR 1004] │\n│ 1002 ╎ [STR 1007] │  │ X3  ╎ [REF 1005] │\n│ 1003 ╎ [STR 1004] │  │ X4  ╎ [STR 1007] │\n│ 1004 ╎ h|2        │  │ X5  ╎ [STR 1007] │\n│ 1005 ╎ [STR 1001] │  │ X6  ╎ [STR 1009] │\n│ 1006 ╎ [STR 1007] │  └─────┴────────────┘\n│ 1007 ╎ f|1        │\n│ 1008 ╎ [STR 1009] │\n│ 1009 ╎ a|0        │\n│ 1010 ╎ [REF 1005] │\n└──────┴────────────┘\n\nW = f(a)\nX = f(a)\nY = f(f(a))\nZ = f(f(a))\n```\n\n## Language ℒ₂ – Flat Resolution\n\nTODO\n\n## Language ℒ₃ – Prolog\n\nTODO\n\n## References\n\n* http://www.ai.sri.com/pubs/files/641.pdf\n* http://wambook.sourceforge.net/wambook.pdf\n* http://stefan.buettcher.org/cs/wam/wam.pdf\n* http://www.cs.ox.ac.uk/jeremy.gibbons/publications/wam.pdf\n* https://gist.github.com/kachayev/b5887f66e2985a21a466\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Richard Hull\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frm-hull%2Fwam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frm-hull%2Fwam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frm-hull%2Fwam/lists"}