{"id":413,"date":"2012-09-07T22:40:04","date_gmt":"2012-09-07T12:40:04","guid":{"rendered":"http:\/\/juliangamble.com\/blog\/?p=413"},"modified":"2013-12-27T10:47:46","modified_gmt":"2013-12-26T23:47:46","slug":"the-little-schemer-in-clojure-chapter-8-friends-and-relations","status":"publish","type":"post","link":"https:\/\/juliangamble.com\/blog\/2012\/09\/07\/the-little-schemer-in-clojure-chapter-8-friends-and-relations\/","title":{"rendered":"The Little Schemer in Clojure \u2013 Chapter 8 \u2013 Friends and Relations"},"content":{"rendered":"<p><em>This is the eighth Chapter of a series of posts about porting\u00a0<a href=\"http:\/\/www.ccs.neu.edu\/home\/matthias\/BTLS\/\">The Little Schemer<\/a>\u00a0to Clojure. You may wish to\u00a0<a href=\"http:\/\/juliangamble.com\/blog\/2012\/07\/20\/the-little-schemer-in-clojure\/\">read the intro<\/a>.<\/em><\/p>\n<p>So far we&#8217;ve covered\u00a0<a href=\"http:\/\/juliangamble.com\/blog\/2012\/07\/20\/the-little-schemer-in-clojure-chapter-1\/\">flat data structures<\/a>,\u00a0<a href=\"http:\/\/juliangamble.com\/blog\/2012\/07\/29\/the-little-schemer-in-clojure-chapter-2\/\">reading flat data structures<\/a>,\u00a0<a href=\"http:\/\/juliangamble.com\/blog\/2012\/08\/03\/the-little-schemer-in-clojure-chapter-3\/\">creating data structures<\/a>,\u00a0<a href=\"http:\/\/juliangamble.com\/blog\/2012\/08\/10\/the-little-schemer-in-clojure-chapter-4-numbers-games\/\">creating a numeric tower<\/a>, working with\u00a0<a href=\"http:\/\/juliangamble.com\/blog\/2012\/08\/17\/the-little-schemer-in-clojure-chapter-5-the-multichapter-chapter\/\">multiple occurrences of a match in the list<\/a>, \u00a0<a href=\"http:\/\/juliangamble.com\/blog\/2012\/08\/19\/the-little-schemer-in-clojure-chapter-6-oh-my-gawd-its-full-of-stars\/\">changing our functions to work with nested lists<\/a>\u00a0and <a href=\"http:\/\/juliangamble.com\/blog\/2012\/08\/31\/the-little-schemer-in-clojure-chapter-7-shadows\/\">building a numerical expression evaluator<\/a>.<\/p>\n<p>This chapter we&#8217;ll look at sets, relations and functions (in the mathematical sense). \u00a0So starting with <code>set?<\/code> let&#8217;s see if a list contains a set of unique items.<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def set_?\r\n  (fn &#x5B;lat]\r\n    (cond\r\n      (null? lat) true\r\n      true (cond\r\n             (member? (first lat) (rest lat)) false\r\n             true (set_? (rest lat))))))\r\n\r\n(println (set_? '(toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (set_? '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Note that this assumes the implementation of <code>member?<\/code> from <a href=\"http:\/\/juliangamble.com\/blog\/2012\/08\/17\/the-little-schemer-in-clojure-chapter-5-the-multichapter-chapter\/\">Chapter 5<\/a>.<\/p>\n<p>Now let&#8217;s simplify our definition of <code>set?<\/code>:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def member\r\n  (fn &#x5B;lat]\r\n    (cond\r\n      (null? lat) true\r\n      (member? (first lat) (rest lat)) false\r\n      true (set? (rest lat)))))\r\n\r\n(println (set_? '(toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (set_? '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now given a non-unique list of items, let&#8217;s return a set of unique items based on the original list with <code>makeset<\/code>:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def makeset\r\n  (fn &#x5B;lat]\r\n    (cond\r\n      (null? lat) '()\r\n      (member? (first lat) (rest lat)) (makeset (rest lat))\r\n      true (cons (first lat) (makeset (rest lat))))))\r\n\r\n(println (makeset '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt; (toasted banana bread with butter for breakfast)\r\n(println (set_? (makeset '(breakfast toasted banana bread with butter for breakfast))))\r\n;\/\/=&gt;true\r\n<\/pre>\n<p>Now we&#8217;ll refactor makeset using our definition of <code>multirember<\/code> from <a href=\"http:\/\/juliangamble.com\/blog\/2012\/08\/17\/the-little-schemer-in-clojure-chapter-5-the-multichapter-chapter\/\">Chapter 5<\/a>:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def makeset\r\n  (fn &#x5B;lat]\r\n    (cond\r\n      (null? lat) '()\r\n      true (cons (first lat) (makeset (multirember (first lat) (rest lat)))))))\r\n\r\n(println &quot;&quot;)\r\n(println &quot;makeset - refactored with multirember&quot;)\r\n(println (makeset '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt; (breakfast toasted banana bread with butter for)\r\n; note other way around\r\n(println (set_? (makeset '(breakfast toasted banana bread with butter for breakfast))))\r\n;\/\/=&gt;true\r\n<\/pre>\n<p>While we&#8217;re looking at sets, let&#8217;s write a function to work out if one set is a <code>subset<\/code> of another:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def subset?\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) true\r\n      true (cond\r\n             (member? (first set1) set2) (subset? (rest set1) set2)\r\n             true false))))\r\n\r\n(println (subset? '(banana butter) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (subset? '(banana butter) '(toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (subset? '(peanut butter) '(toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now we&#8217;ll refactor <code>subset<\/code> to remove the second conditional:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def subset?\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) true\r\n      (member? (first set1) set2) (subset? (rest set1) set2)\r\n      true false)))\r\n\r\n(println (subset? '(banana butter) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (subset? '(banana butter) '(toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (subset? '(peanut butter) '(toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now we&#8217;ll refactor <code>subset<\/code> again to make better use of the trailing final condition:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def subset?\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) true\r\n      true (and\r\n             (member? (first set1) set2)\r\n             (subset? (rest set1) set2)))))\r\n\r\n(println (subset? '(banana butter) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (subset? '(banana butter) '(toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (subset? '(peanut butter) '(toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now we&#8217;ll write <code>eqset<\/code> to see if two sets are equal (regardless of order):<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def eqset?\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (subset? set1 set2) (subset? set2 set1)\r\n      true false)))\r\n\r\n(println (eqset? '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;false\r\n(println (eqset? '(toasted banana bread) '(toasted banana bread)))\r\n;\/\/=&gt;true\r\n(println (subset? '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now we&#8217;ll refactor <code>eqset<\/code> to have only one condition line:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def eqset?\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      true (and\r\n             (subset? set1 set2)\r\n             (subset? set2 set1)))))\r\n\r\n(println (eqset? '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;false\r\n(println (eqset? '(toasted banana bread) '(toasted banana bread)))\r\n;\/\/=&gt;true\r\n(println (subset? '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now we&#8217;ll refactor <code>eqset<\/code> to remove the condition line altogether:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def eqset?\r\n  (fn &#x5B;set1 set2]\r\n      (and\r\n        (subset? set1 set2)\r\n        (subset? set2 set1))))\r\n\r\n(println (eqset? '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;false\r\n(println (eqset? '(toasted banana bread) '(toasted banana bread)))\r\n;\/\/=&gt;true\r\n(println (subset? '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now we&#8217;ll write a test to see if two sets <code>intersect?<\/code>:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def intersect?\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) false\r\n      true (cond\r\n             (member? (first set1) set2) true\r\n             true (intersect? (rest set1) set2)))))\r\n\r\n(println (intersect? '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (intersect? '(toasted banana bread) '(toasted banana bread)))\r\n;\/\/=&gt;true\r\n(println (intersect? '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;true\r\n(println (intersect? '(strawberry yoghurt) '(toasted banana bread )))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now we&#8217;ll refactor intersect? to remove the redundant second conditional:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def intersect?\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) false\r\n      (member? (first set1) set2) true\r\n      true (intersect? (rest set1) set2))))\r\n\r\n(println (intersect? '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (intersect? '(toasted banana bread) '(toasted banana bread)))\r\n;\/\/=&gt;true\r\n(println (intersect? '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;true\r\n(println (intersect? '(strawberry yoghurt) '(toasted banana bread )))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now we&#8217;ll refactor intersect? to make better use of the trailing conditional:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def intersect?\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) false\r\n      true (or\r\n             (member? (first set1) set2)\r\n             (intersect? (rest set1) set2)))))\r\n\r\n(println (intersect? '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;true\r\n(println (intersect? '(toasted banana bread) '(toasted banana bread)))\r\n;\/\/=&gt;true\r\n(println (intersect? '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;true\r\n(println (intersect? '(strawberry yoghurt) '(toasted banana bread )))\r\n;\/\/=&gt;false\r\n<\/pre>\n<p>Now we&#8217;ll actually get the values at the <code>intersect<\/code>ion:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def intersect\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) '()\r\n      (member? (first set1) set2) (cons (first set1) (intersect (rest set1) set2))\r\n      true (intersect (rest set1) set2))))\r\n\r\n(println (intersect '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;(toasted banana bread)\r\n(println (intersect '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;(toasted)\r\n(println (intersect '(strawberry yoghurt) '(toasted banana bread )))\r\n;\/\/=&gt;()\r\n<\/pre>\n<p>Now we&#8217;ll refactor <code>intersect<\/code> to filter out non-members first:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def intersect\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) '()\r\n      (not (member? (first set1) set2)) (intersect (rest set1) set2)\r\n      true (cons (first set1) (intersect (rest set1) set2)))))\r\n\r\n(println (intersect '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;(toasted banana bread)\r\n(println (intersect '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;(toasted)\r\n(println (intersect '(strawberry yoghurt) '(toasted banana bread )))\r\n;\/\/=&gt;()\r\n<\/pre>\n<p>The opposite of getting the intersection of two sets is to get the <code>union<\/code> &#8211; we&#8217;ll do that now:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def union\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) set2\r\n      (member? (first set1) set2) (union (rest set1) set2)\r\n      true (cons (first set1) (union (rest set1) set2)))))\r\n\r\n(println (union '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;(breakfast toasted banana bread with butter for breakfast)\r\n;\/\/ note not a set since not given a set\r\n(println (union '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;(peanut butter for breakfast toasted banana bread)\r\n(println (union '(strawberry yoghurt) '(toasted banana bread )))\r\n;\/\/=&gt;(strawberry yoghurt toasted banana bread)\r\n<\/pre>\n<p>The function next in the line is the <code>complement<\/code> of two sets:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def complement_\r\n  (fn &#x5B;set1 set2]\r\n    (cond\r\n      (null? set1) '()\r\n      (member? (first set1) set2) (complement_ (rest set1) set2)\r\n      true (cons (first set1) (complement_ (rest set1) set2)))))\r\n\r\n(println (complement_ '(toasted banana bread) '(breakfast toasted banana bread with butter for breakfast)))\r\n;\/\/=&gt;()\r\n(println (complement_ '(toasted peanut butter for breakfast) '(toasted banana bread )))\r\n;\/\/=&gt;(peanut butter for breakfast)\r\n(println (complement_ '(strawberry yoghurt) '(toasted banana bread )))\r\n;\/\/=&gt;(strawberry yoghurt)\r\n<\/pre>\n<p>Now we&#8217;ll look at the intersection of more than two sets with <code>intersect-all<\/code>:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def intersect-all\r\n  (fn &#x5B;l-set]\r\n    (cond\r\n      (null? (rest l-set)) (first l-set)\r\n      true (intersect (first l-set) (intersect-all (rest l-set))))))\r\n\r\n(println &quot;&quot;)\r\n(println &quot;intersect-all&quot;)\r\n(println (intersect-all\r\n           '(\r\n              (toasted banana bread)\r\n              (breakfast toasted banana bread with butter for breakfast)\r\n              (toasted peanut butter for breakfast)\r\n              (toasted banana bread ))))\r\n;\/\/=&gt;(toasted)\r\n<\/pre>\n<p>Here the book changes direction &#8211; our work on sets has been a building block for looking at functions and relations. Assuming that we can express a function as a set of value pairs &#8211; we need to be able to have the building blocks to work with pairs. We&#8217;ll start by getting the <code>first<\/code> and <code>second<\/code> value out of a pair:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def first_\r\n  (fn &#x5B;p]\r\n    (cond\r\n      true (first p))))\r\n\r\n(println (first_ '(a b)))\r\n;\/\/=&gt;a\r\n\r\n(def second_\r\n  (fn &#x5B;p]\r\n    (cond\r\n      true (first (rest p)))))\r\n\r\n(println (second_ '(a b)))\r\n;\/\/=&gt;b\r\n<\/pre>\n<p>Next we&#8217;ll add the ability to <code>build<\/code> a pair:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def build\r\n  (fn &#x5B;a b]\r\n    (cond\r\n      true (cons a (cons b '())))))\r\n\r\n(println (build 'a 'b))\r\n;\/\/=&gt;(a b)\r\n<\/pre>\n<p>For the sake of keeping our brain going &#8211; we&#8217;ll get the <code>third<\/code> item of a pair just to keep you wondering:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def third_\r\n  (fn &#x5B;p]\r\n    (cond\r\n      true (first (rest (rest p))))))\r\n\r\n(println (third_ '(a b c)))\r\n;\/\/=&gt;c\r\n<\/pre>\n<p>Now we&#8217;ll look closer at functions. You&#8217;ll remember that for a set of pairs to be a <code>fun<\/code>ction, there must be only one domain value &#8211; ie the first values from a set of pairs must themselves be a set. We&#8217;ll borrow our definition of <code>member*<\/code> from <a href=\"http:\/\/juliangamble.com\/blog\/2012\/08\/19\/the-little-schemer-in-clojure-chapter-6-oh-my-gawd-its-full-of-stars\/\">Chapter 6<\/a>.<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def firsts\r\n  (fn &#x5B;l]\r\n    (cond\r\n      (empty? l) '()\r\n      true (cons (first (first l))\r\n        (firsts (rest l))))))\r\n\r\n(println &quot;&quot;)\r\n(println &quot;firsts&quot;)\r\n(println (firsts '((8 3)(4 2)(7 6)(6 2)(3 4))))\r\n;\/\/=&gt;(8 4 7 6 3)\r\n\r\n(def fun?\r\n  (fn &#x5B;rel]\r\n    (set? (firsts rel))))\r\n\r\n(println &quot;&quot;)\r\n(println &quot;fun? - refactored to use set? and firsts&quot;)\r\n(println (fun? '((4 3)(4 2)(7 6)(6 2)(3 4))))\r\n;\/\/=&gt;false\r\n(println (fun? '((8 3)(4 2)(7 6)(6 2)(3 4))))\r\n;\/\/=&gt;true\r\n(println (fun? '((8 3)(4 2)(7 1)(6 0)(9 5))))\r\n;\/\/=&gt;true\r\n<\/pre>\n<p>Now just in case you ever wanted to reverse the elements in their pairs and order in the list &#8211; we bring you <code>revrel<\/code>. (It is actually a building block for other functions to come).<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def revrel\r\n  (fn &#x5B;rel]\r\n    (cond\r\n      (null? rel) '()\r\n      true (cons\r\n             (build\r\n               (second_ (first rel))\r\n               (first_ (first rel)))\r\n             (revrel (rest rel))))))\r\n\r\n(println (revrel '((4 3)(4 2)(7 6)(6 2)(3 4))))\r\n;\/\/=&gt;((3 4) (2 4) (6 7) (2 6) (4 3))\r\n(println (revrel '((8 3)(4 2)(7 6)(6 2)(3 4))))\r\n;\/\/=&gt;((3 8) (2 4) (6 7) (2 6) (4 3))\r\n(println (revrel '((8 3)(4 2)(7 1)(6 0)(9 5))))\r\n;\/\/=&gt;((3 8) (2 4) (1 7) (0 6) (5 9))\r\n<\/pre>\n<p>So applying what we&#8217;ve just learned &#8211; a full function is one in which both the values of the domain are unique, and the values of the range are unique. We can test this with <code>fullfun?<\/code>:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def fullfun?\r\n  (fn &#x5B;fun]\r\n    (set_? (seconds_ fun))))\r\n\r\n(println (fullfun? '((4 3)(4 2)(7 6)(6 2)(3 4))))\r\n;\/\/=&gt;false\r\n(println (fullfun? '((8 3)(4 2)(7 6)(6 2)(3 4))))\r\n;\/\/=&gt;false\r\n(println (fullfun? '((8 3)(4 2)(7 1)(6 0)(9 5))))\r\n;\/\/=&gt;true\r\n<\/pre>\n<p>A simpler way to express this idea is that the domain of the function is unique &#8211; even if the range values are swapped with the domain values &#8211; we call this <code>one-to-one<\/code>:<\/p>\n<pre class=\"brush: clojure; title: ; notranslate\" title=\"\">\r\n(def one-to-one?\r\n  (fn &#x5B;fun]\r\n    (fun? (revrel fun))))\r\n\r\n(println (one-to-one? '((4 3)(4 2)(7 6)(6 2)(3 4))))\r\n;\/\/=&gt;false\r\n(println (one-to-one? '((8 3)(4 2)(7 6)(6 2)(3 4))))\r\n;\/\/=&gt;false\r\n(println (one-to-one? '((8 3)(4 2)(7 1)(6 0)(9 5))))\r\n<\/pre>\n<p>You can see this running <a href=\"http:\/\/ideone.com\/a5yls\">here<\/a>.<\/p>\n<p><strong>Conclusion<\/strong>:<br \/>\nThis chapter we&#8217;ve looked at sets, relations and functions (in the mathematical sense). We haven&#8217;t really added any new primitives this chapter (thank goodness!).<\/p>\n<p>In total our primitives so far are: <code>atom?<\/code>, <code>null?<\/code>, <code>first<\/code>, <code>rest<\/code>, <code>cond<\/code>, <code>fn<\/code>, <code>def<\/code>, <code>empty?<\/code>,<code>=<\/code>, <code>cons<\/code>, <code>add1,<\/code>, <code>sub1<\/code>, <code>one?<\/code> and <code>expt<\/code>. These are all the functions (and those in the chapters to come) that we\u2019ll need to implement to get our metacircular interpreter working.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the eighth Chapter of a series of posts about porting\u00a0The Little Schemer\u00a0to Clojure. You may wish to\u00a0read the intro. So far we&#8217;ve covered\u00a0flat data structures,\u00a0reading flat data structures,\u00a0creating data structures,\u00a0creating a numeric tower, working with\u00a0multiple occurrences of a &hellip; <a href=\"https:\/\/juliangamble.com\/blog\/2012\/09\/07\/the-little-schemer-in-clojure-chapter-8-friends-and-relations\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[3,12],"tags":[],"class_list":["post-413","post","type-post","status-publish","format-standard","hentry","category-clojure","category-thelittleschemer"],"_links":{"self":[{"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/posts\/413","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/comments?post=413"}],"version-history":[{"count":13,"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/posts\/413\/revisions"}],"predecessor-version":[{"id":573,"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/posts\/413\/revisions\/573"}],"wp:attachment":[{"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/media?parent=413"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/categories?post=413"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/juliangamble.com\/blog\/wp-json\/wp\/v2\/tags?post=413"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}