Search code examples
clojurelispcommon-lisp

Scheme to Clojure Function (subst)


I am reading Paul Graham's The Roots of Lisp

I have tried converting the function subst on page 5, which is defined like this:

(defun subst (x y z)
  (cond ((atom z)
         (cond ((eq z y) x)
               ('t z)))
        ('t (cons (subst x y (car z))
                  (subst x y (cdr z))))))

To its corresponding Clojure implementation. I do not have production experience in either languages (I have been reading Clojure), so any help would be appreciated since I am reading this to understand the roots of LISP. The closest I came to was this (but it is horribly wrong):

(defn subst
 [x y z]
 (if (not (nil? z)) z x)
     (if (= z y) x z)
    (cons (subst x y (first z))
          (subst (x y (rest z)))))

Solution

  • This is how I would do it, including a unit test to verify:

    (ns tst.demo.core
      (:use tupelo.core tupelo.test)
      (:require [clojure.walk :as walk]))
    
    (defn subst
      [replacement target listy]
      (walk/postwalk (fn [elem]
                       (if (= elem target)
                         replacement
                         elem))
        listy))
    
    (dotest
      (is= (subst :m :b [:a :b [:a :b :c] :d])
        [:a :m [:a :m :c] :d]))
    

    However, I would not spend a lot of time reading 40-year old texts on Common Lisp, even though I think Paul Graham's book Hackers & Painters is quite mind blowing.

    Clojure has evolved the state-of-the-art for lisp by at least one order-of-magnitude (more like 2, I would say). Major improvements include the use of the JVM, persistent data structures, concurrency, syntax, and data literals, just to name a few.

    Please see this list of Clojure learning resources, and maybe start with Getting Clojure or similar.


    Update

    More from Paul Graham on Clojure

    enter image description here