Monday, February 27, 2012

On Lisp in Clojure ch 2 (2.1 - 2.3)

This is the first post translating the examples in On Lisp into Clojure. The book is available to read for free online, so please read the book, and check here if you are not sure how it applies to Clojure.

In the book, chapter 1 described the extensibility and flexibility of Lisp. In short, it lays out the reason I am going through the book. The few code samples in this chapter didn't seem to benefit from translation though.

Chapter 2 is about Functions. Section 2.1 discusses functions as a data type. It doesn't contain any examples.

Section 2.2 Defining Functions

;; double function
(defn double [x] (* x 2))

;; invoking double
(double 1)

;; referring to the function as a variable
#'double
(= #'double (first (list #'double)))

;; lambdas are defined two ways in Clojure
(fn [x] (* x 2))
#(* % 2)

;; invoking an anonymous function
((fn [x] (* x 2)) 3)
(#(* % 2) 3)

Next, the book assigns a variable double, and shows that the function and the variable can exist side by side with the same name. This works in common lisp, because it has a separate namespace for functions and variables it does not work in Clojure. CLISP is said to be a LISP-2 (Two namespaces) While Clojure (and scheme) are LISP-1s.

;; we can assign assign a function to a variable
(def x #'double)
(x 2)

Section 2.3 Functional Arguments

;; four expressions with the same effect
(+ 1 2)
(apply + '(1 2))
(apply + 1 '(2))
(apply + 1 2)

;; funcall doesn't exist in Clojure

;; map applies a function to each argument in a list
(map #(+ % 10) '(1 2 3))
(map + '(1 2 3) '(10 100 1000))

;; sort is ascending by default
(sort '(1 4 2 5 6 7 3))
;; to specify sort order, pass the function then the list
(sort > '(1 4 2 5 6 7 3))

;; instead of remove-if, in Clojure use filter, true values are returned
(filter odd? '( 1 2 3 4 5 6 7))
;; pred can also be an anonymous function
(filter #(= 0 (rem % 3)) '(1 2 3 4 5 6 7 8 9))

;; our-remove-if was implemented with recursion in the book.
(defn our-remove-if [pred lst]
  (if (empty? lst)
    nil
    (if (pred (first lst))
      (our-remove-if pred (rest lst))
      (cons (first lst) (our-remove-if pred (rest lst))))))

(our-remove-if even? '(1 2 3 4 5))

;; The actual filter function is implemented with a lazy sequence
;; You can see the implementation of core functions with (source ...)
(source filter)

I am going to stop here, because section 2.4 is a big enough topic that it should have its own space.

2 comments:

  1. Note that #' (var-quote) in clojure has a completely different meaning from #' (function) in common lisp and it's usually a mistake to copy usage of #' in CL to clojure, even though it tends to more-or-less work because #'foo is callable. As far as I can tell, you can drop the #' in all the clojure code in this posting.

    ReplyDelete