On Lisp – chapter 2

18 11 2009

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
Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: