Tuesday, April 24, 2012

On Lisp in Clojure chapter 7 (7.1 - 7.4)

I am continuing to translate the examples from On Lisp by Paul Graham into Clojure. You can find links to the other posts in this series and the code on the github repository for this project.

Stuart Halloway has also translated this chapter into Clojure on his blog. I definitely recommend reading that.

In Chapter 7 we finally get to macros.

Section 7.1 How Macro's Work

The nil! macro Graham defines sets the variable passed in to nil. Values in Clojure are immutable by default, but there are special constructs for doing mutation. One is the atom.

;; set atom to nil
(def x (atom 0))
(reset! x 5)

(defmacro atomnil! [var]
  (list 'reset! var nil))

(atomnil! x)

Ref's must be mutated within a transaction, which is done with dosync.

;; set ref to nil
(def y (ref 0))
(dosync
 (ref-set y 5))

(defmacro refnil! [var]
  (list 'dosync (list 'ref-set var nil)))

(refnil! y)

Section 7.2 Backquote

Clojure also uses the backquote, usually referred to as the syntax quote which can be unquoted. In Clojure unqouting done with the tilde ~ instead of the comma used in Common Lisp.

(defmacro atomnil! [var]
  `(reset! ~var nil))

(defmacro refnil! [var]
  `(dosync (ref-set ~var nil)))


;; 3 way numerical if
(defmacro nif [expr pos zero neg]
  `(cond
    (< ~expr 0) ~neg
    (> ~expr 0) ~pos
    :else ~zero ))

(nif -1 "pos" "zero" "neg")

Just as the , was replaced by ~ `@ becomes ~@

(def b '(1 2 3))

`(a ~b c)
;; => OnLisp.ch7/a (1 2 3) OnLisp.ch7/c

`(a ~@b c)
;; => OnLisp.ch7/a 1 2 3 OnLisp.ch7/c

Clojure's do is the equivelant of progn in Common Lisp. It executes a series of statements and returns the value of the last expression.

(defmacro our-when [test & body]
  `(if ~test
     (do ~@body)))

(our-when (< 1 2)
          (println "This is a side effect")
          (println "This is another side effect")
          "this is a value")

Section 7.3 Defining Special Macrosk

Clojure does not contain a member function, but we can define one, and also define the memq macro which does the same thing.

(defn member [obj lst]
  (some (partial = obj) lst))

(defmacro memq [obj lst]
  `(some (partial = ~obj) ~lst))

Clojure already has a while loop, which is good, since this implementation isn't very durable.

(defmacro our-while [test & body]
  `(if ~test
    (do
      (swap! ~test not)
      ~@body)))

(our-while (atom true) (println "side effect") "Value")

Section 7.4 Testing Macro Expansion

I like the pretty print macro expansion.

(defmacro mac [expr]
  `(clojure.pprint/pprint (macroexpand-1 '~expr)))

(mac (our-while (atom true) (println "side effect") "Value"))

That seems like a good amount for one post. Will pick up the second half of chapter 7 next time.

Saturday, April 21, 2012

Hello World in ClojureScript

Hello CLJS

Edit October 18, 2013

If you want to get started with ClojureScript I highly recommend that you read Mimmo Cosenza's series of tutorials at https://github.com/magomimmo/modern-cljs . This is the best resource I have found on learning ClojureScript. Please check it out, and don't waste a second reading my old post.

There is probably no reason to keep the original text, but in case there is some value in it I have overlooked, I will leave it unchanged.


I have wanted to learn about ClojureScript, but I haven't known where to start. Like so much in Clojure it turns out to be much simpler than I expected. The instructions for the various projects are each very clear, but I still found it overwhelming at first. Rather than go into detail, I will try to give an overview and link to the related projects.

The appeal of JavaScript, and thus ClojureScript, is that it can be used in so many ways. For example, you can use cljs to do client-side programming in a traditional web application, to do all of the dynamic code in a single page web app, or to do server side scripting in node.js.

Overview

ClojureScript, wherever you use it is compiled to JavaScript. It is the .js file generated by the compiler that you will refer to in your application.

While it is possible to use the ClojureScript compiler directly, the recommended method is to use lein-cljsbuild. If you are creating a new noir web application that you want to use ClojureScript with you can use the cljs-template which will install and configure lein-cljsbuild for you. For anything but a brand new noir project, you will need to set up lein-cljsbuild yourself.

Again, following the instructions on lein-cljsbuild is all you need to do, but I like to see the big picture before I get to the details.

To install cljs-build you add a reference to it with a :pluggins tag on an existing project that you created with leiningen. Configure the plugin by adding :cljsbuild tag, also in the project definition. specifying a path to your ClojureScript source files. If you are writing scripts to use in node.js you will need to specify :target :nodejs in the compiler options. Leiningen will actually install the plugin the first time you try to compile your script files.

Example

I will do a quick walkthrough, to make sure everything is working. I am going to create a very basic script that simply displays an alert when a page is loaded. I will then create a simple html file that will host that script.

My instructions will be very similar to the instructions in the lein-cljsbuild read me, except that I structure my source and destination folders a little differently. Assuming you have Leiningen 1.7 or later installed at the terminal create a new project:

lein new hello-cljs
cd hello-cljs

Edit the project.clj file, adding a :pluggins tag and setting the build options:

(defproject hello-cljs "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.3.0"]]
  :plugins [[lein-cljsbuild "0.1.8"]]
  :cljsbuild {
             :builds [{
                       :source-path "src-cljs"
                       :compiler {
                                  :output-to "web/js/main.js"
                                  :optimzations :whitespace
                                  :pretty-print true}}]})

Create a src-cljs directory, and in it create a file called main.cljs. Your main.cljs should contain the following:

(ns hello-cljs.main)

(js/alert "Hello from ClojureScript.")

From your project's root directory compile the ClojureScript to javascript by typing:

lein cljsbuild once

Compiling will create the destination folders, if they do not already exist.

Go to your web directory, and create a file hello.html:

<html>
 <head>
    <title>Hello CLJS</title>
  </head>
  <body>
    You should have seen an alert if everything is working.
    <script type="text/javascript" src="js/main.js"<>/script>
  </body>
</html>

Not a project that will win any awards, but it is nice to know you are set up correctly.

I wanted to mention one additional thing. In this example we compiled the cljs file to js using the command "lein cljsbuild once". Instead, you can use the command "lein cljsbuild auto" and cljsbuild will monitor your cljs source code directory and recompile any file that changes. Another good option to know is "lein cljsbuild clean" which will delete the compiled js file.

Monday, April 16, 2012

On Lisp in Clojure (chapter 6)

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

I have placed the examples from the first 6 chapters on GitHub. The readme links to all of the posts in this series. (Except this one... a fact without a time is incomplete).

Section 6.1 Networks

I have represented the nodes as a map of maps.

(def nodes
  {:people {:question "Is the person a man?" :yes :male :no :female}
   :male {:question "Is he dead?" :yes :deadman :no :liveman }
   :deadman {:question "Was he American?" :yes :us :no :them}
   :us {:question "Is he on a coin?" :yes :coin :no :cidence}
   :coin {:question "Is the coin a penny?" :yes :penny :no :coins}
   :penny {:answer "Lincoln"}})

(defn ask-question [question]
  true)

Since the network is incomplete, I decided not to implement the IO. Making ask-question always return true did require one change from Graham's example. Instead of asking if the person is living, I ask if he is dead, since I only go down the true line.

(defn run-node [name nodes]
  (let [n (name nodes)]
    (if-let [result (get n :answer)]
      result
      (if (ask-question (:question n))
        (recur (:yes n) nodes)
        (recur (:no n) nodes)))))

(run-node :people nodes)

Of course, we want to be able to add nodes programmatically. Instead of optional parameters, in the Clojure implementation we can define a multiple arity function to add both branches and leaves.

(defn add-node
  ([nodes tag answer]
     (conj nodes {tag {:answer answer}}))
  ([nodes tag question yes no]
     (conj nodes {tag {:question question :yes yes :no no}})))

Because nodes is immutable, the following two calls each return a new map that is the original map, plus their one node.

(add-node nodes :liveman "Is he a former president" :texas :california)
(add-node nodes :texas "George W Bush")

The Clojure threading macro, ->, makes it easy to insert the result of one function as a parameter of a second function. The following block creates a new set of nodes with the :liveman tag and passes this to the function that adds the :texas tag. In the end, we get a new map that has both tags added.

(-> 
    (add-node nodes :liveman "Is he a former president" 
         :texas :california)
    (add-node :texas "George W Bush"))

Section 6.2 Compiling Networks

In this section, Graham rewrote the network, adding the function calls to the nodes themselves.

The add-node function becomes

(defn add-node2
  ([nodes tag answer]
     (conj nodes {tag answer}))
  ([nodes tag question yes no]
     (conj nodes {tag (if (ask-question question) 
                           (yes nodes) 
                           (no nodes))})))

I added a couple of nodes, and was surprised by the results:

(def node2
  (-> 
      (add-node2 {} :people "Is the preson a man?" :male :female)
      (add-node2 :male "Is he dead?" :deadman :liveman)))
node2
;; => {:male nil, :people nil}

I decided to start adding from the bottom up:

(def node2
  (-> (add-node2 {} :penny "Lincoln")
      (add-node2 :coin "is the coin a penny?" :penny :coins)
      (add-node2 :us "Is he on a coin" :coin :cindence)))
node2
;; =>  {:us "Lincoln", :coin "Lincoln", :penny "Lincoln"}

I tried rewriting my add-node2 function.

(defn add-node2
  ([nodes tag answer]
     (conj nodes {tag answer}))
  ([nodes tag question yes no]
     (conj nodes
           {tag
            (if ((fn [x] (ask-question x)) question )
              (yes nodes) (no nodes) )})))

I still got the same results.

I tried declaring, but not defining ask-question. When I called add-node2 I got an error that ask-question had not been defined. I tried referring to node2 from another namespace, and still every node evaluated to "Lincoln".

I rewrote the ask-question function to actually ask a question:

(defn prompt [text]
  (do
    (println text)
    (read-line)))

(defn ask-question [question]
  (prompt question))

Now, I get prompted with the question for each node I add. Again, I tried this from a different namespace, and again I was prompted.

I wonder if we have reached the limit of functions. Stay tuned, Chapter 7 begins our journey into the world of macros.

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.

Monday, April 2, 2012

On Lisp in Clojure ch 4 (4.5 - 4.8)

I am continuing to translate examples from On Lisp by Paul Graham into Clojure. Today I will go over the last few sections of chapter 4.

Section 4.5 Mapping

The map-> function is more concise in Clojure. I also think it is clearer to see that what it is doing is generating a sequence, and mapping a function over that sequence.

In the sample call to map-> I thought it would be fun to describe the functions being passed in 3 different ways, just for variety.

(defn map-> [fn a test-fn succ-fn]
  (map fn (take-while test-fn (iterate succ-fn a))))
 
(map-> inc -2 #(< % 2) (partial + 0.5 ))

Graham presents functions that take in two lists and map a function over the two lists without joining them first. He explains that it doesn't make sense to cons up a list to just pass it to another function and forget it.

Sequences in Clojure are either lazy or persistent. In either case there shouldn't be any penalty for joining the list before passing it into a function.

Section 4.6 I/O

Translating these examples was more about completeness and curiosity. If you are interacting with your program, you will probably use the repl. If you are making something for public consumption, Seesaw is great for doing desktop ui, and Noir is great for doing web interfaces.

(defn read-list []
  (str \( (read-line) \)))

(defn prompt [text]
  (do
    (println text)
    (read-line)))

(defn break-loop [fn quit]
  (let [x (read-string (prompt (str "type " quit " to quit")))] 
    (if (not (= x quit))
      (do
        (fn x)
        (recur fn quit)))))

(break-loop #(println (eval %)) :q)

Section 4.7 Symbols and Strings

Clojure's str function can turn numbers and symbols into strings, and is variadic:

(str Math/PI " pieces of " 'pi)
;;seq can convert strings into sequences of characters
(seq "bomb")
;; => \b \o \m \b

;;strings can be converted to symbols, with or without namespaces
(symbol "foo")
(symbol "some-ns" "foo")

;;Clojure also adds keywords, which you can convert to from strings:
(keyword "foo")
(keyword "some-ns" "foo")

;;If you are not qualifying the keyword with a namespace, you can also create a keyword directly from a symbol
(keyword 'foo)
(keyword "some-ns" (str 'foo))

Section 4.8 Density

This section doesn't have any examples. Graham says that writing utility functions makes your code more concise, which in the long run makes it more readable. Clojure's built in utilities also make code very concise, and also make for a common vocabulary for programmers.