Herr-Norbert.de

Some random rants

Write Your Own Let-Macro

I am currently reading Structure and Interpretation of Computer Programs and stumbled upon the mention that closures could be used to implement the let-function. Next thing I knew, the Clojure REPL was running …

The First Try

my-let.clj
1
2
3
4
5
6
7
8
9
10
user>(defmacro my-let [bindings & body]
`((fn [~@(flatten (partition 1 2 bindings))]
~@body)
~@(flatten (partition 1 2 (rest bindings)))))
user> (macroexpand '(my-let [a 6 b 7] (* a b)))
((clojure.core/fn [a b] (* a b)) 6 7)
user> (my-let [a 6 b 7] (* a b))
42

The basic idea is to generate a closure via the fn-function, set the binding names as parameter names and invoke the function with the binding values.

As you can see the basic binding functionality is working. But there are still two problems. First you can only bind primitive values otherwise the flatten-function would destroy the passed in nested lists. Second you can not access a preceding binding in a succeeding one.

my-let.clj
1
2
3
4
5
6
7
;; Problem 1
user> (macroexpand '(my-let [a 6 b (+ 3 4)] (* a b)))
((clojure.core/fn [a b] (* a b)) 6 + 3 4)
;; Problem 2
user> (macroexpand '(my-let [a 6 b a] (* a b)))
((clojure.core/fn [a b] (* a b)) 6 a)

The Second Try

To sort out the problems I switched to nested closures:

my-let2.clj
1
2
3
4
5
6
7
8
9
10
11
12
user> (defmacro my-let2 [bindings & body]
(if (seq bindings)
`((fn [~(first bindings)]
(my-let2 ~(rest (rest bindings)) ~@body))
~(second bindings))
`(eval ~@body)))
user> (my-let2 [a 6 b (+ 3 4)] (* a b))
42
user> (my-let2 [a 6 b a] (* a b))
36

The idea behind this solution is to generate nested closures so that preceding bindings can be accessed via the parameter of the outer closures. As it turns out both problems get fixed by this approach.

The main challenge in writing the second macro was the (eval ~@body) part. In the example the form (* a b) will be wrapped in another list because body is an optional parameter. To get rid of the extra parentheses unquote-splicing ~@ could be used. Sadly, well actually it makes sense, ~@ can only be used in already escaped lists. Just wrapping another list around wouldn’t make any sense, ~@ just got rid of it. After a long time of try and error I finally found the eval solution.

Conclusion

This little example demonstrates once again how powerful Lisp / Clojure and Macros can be. And don’t forget to read SICP.

I just described the basic idea behind the solution. If you have any further questions feel free to contact me or write a comment.

Google Web Fonts

I really like the idea of web fonts, so I wondered how the blog would look like with different fonts.

If you’re searching the web for web fonts you eventually stumble upon Google Web Fonts or lately Google Web Font Directory. So I used the Google fonts to customise the blog a little bit.

The required steps are pretty easy, straight forward and commendably documented on the font site:

  1. Choose a font in the Google Web Font Directory
  2. Copy the displayed JavaScript into youre site / template
  3. Modify your CSS to use the selected font

If you want a more direct feedback you could use the Google Font Previewer for Chrome. With this plugin you can change the font settings of the current page and have a look at different designs.

Google Font Previewer

Oh-my-zsh

I few days ago I stumbled upon oh-my-zsh. It’s a collection of scripts, plugins and themes to manage and extend the zsh shell.

I am not a shell ninja, nevertheless I like a good shell configuration and oh-my-zsh is really great in this sense.

The plugins and themes are especially noteworthy. Have a look at the next screenshot. It shows a really informative prompt and the git status from the current directory.

screenshot

Assoc vs. Assoc-in vs. Update-in

Currently I am fighting some performance issues in Clojure. While I was looking out for some tips I came across the somewhat famous blog post Clojure performance tips. Now I want to add one of my own.

Assoc vs. Assoc-in vs. Update-in

Assoc, assoc-in and update-in can be used to update data structures. While assoc only allows updates on the first level of the structure, assoc-in and update-in expect some kind of path expression pointing at the value to update and a function to produce a new value. Some examples can be found on ClojureDocs.

So, how is the performance of this functions? I only did some microbenchmarks, so don’t think to much of them.

First lets have a look at update-in. To compare the function we increment the value of :value inside a nested map.

update-in.clj
1
2
3
4
5
6
7
8
9
10
11
user> (dotimes [_ 5]
(time
(dotimes [_ 1000000]
(let [x {:stats {:value 0}}]
(update-in x [:stats :value] inc)))))
"Elapsed time: 1915.204366 msecs"
"Elapsed time: 1905.402848 msecs"
"Elapsed time: 1919.48168 msecs"
"Elapsed time: 1919.289938 msecs"
"Elapsed time: 1954.808177 msecs"
nil

As you can see update-in is a very concise function and I would use it in most cases.

assoc-in.clj
1
2
3
4
5
6
7
8
9
10
11
12
user> (dotimes [_ 5]
(time
(dotimes [_ 1000000]
(let [x {:stats {:value 0}}]
(assoc-in x [:stats :value]
(inc (get (get x :stats) :value)))))))
"Elapsed time: 1207.653239 msecs"
"Elapsed time: 1192.098058 msecs"
"Elapsed time: 1188.202821 msecs"
"Elapsed time: 1191.817293 msecs"
"Elapsed time: 1183.57983 msecs"
nil

Assoc-in isn’t that concise, you manually have to read and update the value, but it’s almost double as fast as update-in.

assoc.clj
1
2
3
4
5
6
7
8
9
10
11
12
user> (dotimes [_ 5]
(time
(dotimes [_ 1000000]
(let [x {:stats {:value 0}}]
(assoc x :stats (assoc (get x :stats) :value
(inc (get (get x :stats) :value))))))))
"Elapsed time: 576.143596 msecs"
"Elapsed time: 571.017181 msecs"
"Elapsed time: 553.624249 msecs"
"Elapsed time: 551.965917 msecs"
"Elapsed time: 549.777064 msecs"
nil

The assoc version looks kind of messy but it’s the fastest one so far and doubles the performance of assoc-in. You can clean it up a little and make it even faster by extracting intermediate results. I don’t know exactly why local variables should make the it faster (perhapes some kind of JIT-magic?), so test it yourself.

assoc-2.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
user> (dotimes [_ 5]
(time
(dotimes [_ 1000000]
(let [x {:stats {:value 0}}
stats (get x :stats)
value (get stats :value)
inc-value (inc value)
inc-stats (assoc stats :value inc-value)]
(assoc x :stats inc-stats)))))
"Elapsed time: 553.294597 msecs"
"Elapsed time: 539.322251 msecs"
"Elapsed time: 529.916189 msecs"
"Elapsed time: 531.741025 msecs"
"Elapsed time: 532.512921 msecs"
nil

Summary

If you really need performance you could think about favoring assoc over the other two functions. But beware the messier code!

Text in Quotes

In the last few days I am wandering in the Land of Lisp and occasionally wondering if some Common Lisp constructs can be converted to Clojure.

One of these things is the quoting of text lists.

list.cl
1
`(there is a ,(caddr edge) going ,(cadr edge) from here.)

This form will evaluate to something like (THERE IS A DOOR GOING WEST FROM HERE.). Now, is there a way to do a simillar thing in Clojure?

list.clj
1
2
user> '(My first test list)
(My first test list)

Simple quotes work as expected but how can we evaluate an expression inside the quote?

list-2.clj
1
2
3
4
user> '(My ~(inc 1) test list)
(My (clojure.core/unquote (inc 1)) test list)
user> `(My ~(inc 2) text list)
(user/My 3 user/text clojure.core/list)

The first form unquotes the expression, by the ~ character, but it didn’t get evaluated. In the second example, the third list, the expression does get evaluated but the output is kind of ugly. Please notice the first character, the syntax-quote ` (a backquote). This quote resolves the symbols in the current namespace and prints the fully quallified name like namespace/name or fully.qualified.Classname. You can get more information on special reader/macro characters at The Reader.

So it seems there is no nice way to translate this Common Lisp construct to Clojure. If you do know one, please let me know.