Tuesday, April 10, 2012

On Lisp in Clojure ch 5

I am continuing to translate the examples from On Lisp into Clojure.

Michael Fogus has already translated some of the examples from this chapter into Clojure.

Section 5.1 Common Lisp Evolves

Clojure has "filter" which returns a lazy sequence of items for which a function is true.

(filter even? (range 10))
;; => (0 2 4 6 8)

(filter (complement even?) (range 10))
;; -> (1 3 5 7 9)


(defn joiner [obj]
  (cond
   (sequential? obj) (partial conj obj)
   (number? obj) (partial + obj)))

(defn make-adder [n]
  (partial + n))

Section 5.2 Orthogonality

In Clojure configuration is usually done with vectors and maps, which are immutable, so instead of updating them you would replace them with a new copy.

(assoc {:a 1 :b 2} :b 3)

Changing properties happens a lot more when interoperating with Java. Dave Ray's Seesaw tutorial gives an example of reading and setting properties using Swing.

(def f (frame :title "Getting to know Seesaw"))
…

; The properties of a widget can be queried ...
(config f :title)
;=> "Get to know Seesaw"

; ... and modified
(config! f :title "No RLY, get to know Seesaw!") 
;=> #

The config function is a seesaw function, not a clojure function.

Section 5.3 Memoizing

Memoize is built in to Clojure.

(defn slow [x]
  (do (Thread/sleep 5000) x))
 
(def slow (memoize slow))

(slow 1)

Section 5.4 Composing Functions

Clojure has comp to do compositions:

((comp inc *) 2 2)
;; => 5

Clojure also has a function called 'juxt' which independently applies a series of functions to a single data structure.

  
((juxt inc dec) 2)
;; => [3 1]

Section 5.5 Recursion on Cdrs

This section I found a bit challenging. I thought I was fine with functions returning functions and recursion, but somehow functions returning recursive functions took me a while to get my head around.

First the examples of recursive functions:

(defn our-length [lst ]
  (loop [lst lst count 0]
    (if (seq lst)
      (recur (rest lst) (inc count))
      count )))

(defn our-every [fn lst]
  (loop [lst lst result true]
    (if (seq lst)
      (recur (rest lst)
             (and result (fn (first lst))))
      result)))

And now a function that returns a recursive function:

(defn lrec [trans base]
  (fn [lst]
    (loop [lst lst result base]
      (if (seq lst)
        (recur (rest lst) (trans (first lst) result))
        result))))

((lrec (fn [new acc] (inc acc)) 0) [2 4 6])
((lrec (fn [new acc] (and acc (even? new))) true) [2 4 6 7])

Section 5.6 Recursion on Subtrees

Working with trees in Clojure is done with clojure.zip. I still am not familiar enough with trees to do anything but plagiarize. Instead of that, I will recommend Brian Marick's tutorial on Clojure.zip.

Section 5.7 talks about a behavior of the Common Lisp compiler. I don't know if an analog exists in Clojure. I am just going to skip it.

No comments:

Post a Comment