Here’s the 2nd chapter of On Lisp translated to Clojure. I’m still learning Clojure and if you have any suggestions I would love to hear them. I am also working on the other chapters and will post them up as and when I finish them
;;page 10
(defn dbl [x]
(* x 2))
(dbl 1)
dbl
;; page 11
(= dbl (first (list dbl)))
;; There are 2 ways to create anonymous functions in Clojure,
;; the #(...) syntax creates a function with the %/%1 %2 %3 as
;; the args. "fn" also create anonymous functions but these
;; can be named as well as have nested anonymous functions.
#(* % 2)
(fn [x] (* x 2))
(fn dbl [x] (* x 2))
(dbl 3)
(#(* % 2) 3)
;; page 13
;; In clojure, which is a lisp-1, there is a single namespace for
;; variables and functions, there is also a single function resolve
;; which resolves a symbol
(resolve 'dbl)
(def x conj)
;; In this case, the result is true, since we're testing the same
;; object for equality
(= x conj)
;; In this case, the result is false, since 'x resolves to
;; user/x while 'conj resolves to clojure.core/conj. They're
;; different objects
(= (resolve 'x) (resolve 'conj))
(defn dbl [x]
(* x 2))
;; Clojure only allows you to bind to a symbol using
;; def, defn and let
(def dbl #(* % 2))
;; (def (symbol "dbl") #(* % 2)) is not valid clojure,
;; does anyone know an alternative.
(eval `(def ~(symbol "dbl") ~#(* % 2)))
;; page 13
(+ 1 2)
(apply + '(1 2))
(apply (resolve '+) '(1 2))
(apply #(+ %1 %2) '(1 2))
(apply + 1 2 '(3 4))
;; Clojure is a Lisp-1 so no need for funcall
;; page 14
(map #(+ % 10) '(1 2 3))
(map + '(1 2 3) '(10 100 1000))
(sort < '(1 4 2 5 6 7 3))
(remove even? '(1 2 3 4 5 6 7))
;; page 15
(defn our-remove-if [f lst]
(if (empty? lst)
'()
(if (f (first lst))
(recur f (rest lst))
(conj (our-remove-if f (rest lst)) (first lst)))))
;; Not a true implementation, but condp is just so cool
(defn behave [animal]
(condp = animal
'dog "bark"
'rat "squeak"
'cat "scratch-carpet"))
;; page 16
(let [y 7]
(defn scope-test [x]
(list x y)))
;; page 17
(let [y 5]
(scope-test 3))
;; page 18
(defn list+ [lst n]
(map #(+ % n) lst))
(list+ '(1 2 3) 10)
;; Since clojure is purely functional, the only way to cause mutable
;; changes is to use atoms, refs and agents. Here I use atoms.
(let [counter (atom 0)]
(defn new-id []
(swap! counter inc))
(defn reset-id []
(reset! counter 0)))
(defn make-adder [n]
#(+ % n))
;; page 19
(def add2 (make-adder 2))
(def add10 (make-adder 10))
(add2 5)
(add10 3)
(defn make-adderb [n]
(let [n (atom n)]
(fn [x & change]
(if (and (not (empty? change)) (first change))
(reset! n x)
(+ x @n)))))
(make-adderb 1)
(def addx (make-adderb 1))
(addx 3)
(addx 100 true)
(addx 3)
;; page 20
(defn make-dbms [db]
(let [db (atom db)]
{:lookup #(@db %)
:insert (fn [k v] (swap! db #(assoc % k v)))
:delete (fn [k] (swap! db #(dissoc % k)))}))
(def cities (make-dbms {:boston 'US :paris 'France}))
((cities :lookup) :boston)
((cities :insert) :london 'England)
((cities :lookup) :london)
(defn lookup [k db]
((db :lookup) k))
;; page 22
;; Clojure doesn't require labels, again because it's a Lisp-1
(let [incr #(inc %)]
(incr 3))
;; In clojure let is let*, so y here will be 10,
;; however, let does not allow self referential
;; bindings
(let [x 10
y x]
y)
(defn count-instances [obj lsts]
(let [instances-in (fn instances-in [lst]
(if (not (empty? lst))
(+ (if (= (first lst) obj) 1 0)
(instances-in (rest lst)))
0))]
(map instances-in lsts)))
(count-instances 'a '((a b c) (d a r p a) (d a r) (a a)))
;; The JVM does not have support for Tail Call Optimization (yet),
;; use the recur keyword for self recursion and trampoline for
;; mutual recursion
(defn our-length [lst]
(if (empty? lst)
0
(inc (our-length (rest lst)))))
;; page 23
(defn our-find-if [f lst]
(if (f (first lst))
(first lst)
(recur f (rest lst))))
(defn our-length [lst]
(let [rec (fn [lst acc]
(if (empty? lst)
acc
(recur (rest lst) (inc acc))))]
(rec lst 0)))
;; page 24
(defn triangle [n]
(let [tri (fn [c n]
(if (zero? n)
c
(recur (+ n c) (dec n))))]
(tri 0 n)))
(triangle 6)
;; All clojure code, before it is run, is transformed into JVM bytecode, there
;; is also the option of Ahead Of Time (AOT) compilation
Advertisement