Dahlia Bock

22Nov/092

Clojure: Return values

Like in Ruby, there is no explicit call in a function to return values, the last expression of a function is evaluated and used as its return value.

Consider the following 2 functions:

(defn hello-with-println [name]
    (println "Hello," name))


(defn hello-with-str [name]
    (str "Hello, " name))

The first function when evaluated on the REPL (read-eval-print-loop), which is an interactive programming environment, returns the following:


user=> (hello-with-println "punk")
Hello, punk
nil

The second function returns:


user=> (hello-with-str "munk")
"Hello, munk"

At first glance, these two functions seem to be doing almost the same thing - takes in a string input, which is a name, and outputs a string that says Hello to that name. However, hello-with-println returns nil while hello-with-str returns the evaluation of the str function.

This can be proven further with special variables in the REPL. When working within the REPL, the results of evaluating the three most recent expressions are stored in the special variables *1, *2 and *3. If I call hello-with-println twice with the inputs "munk" and "punk" and use the special variables *1 and *2 to get the results of those expressions, I get the following:


user=> (str *1 " and " *2)
" and "

If I do the same with hello-with-str, I get the following output:


user=> (str *1 " and " *2)
"Hello, punk and Hello, munk"

When hello-with-println was used, there were no return values so the special variables were empty unlike in hello-with-str.

18Nov/090

Clojure: Getting back to the basics – Lexical Scoping

Functional programming has always been a nightmare for me and it started off in college with a class called 15-212: Principles of Programming, which was taught in SML. Almost everything that was taught in that class went over my head and it's a miracle that I managed to get a B for it. When I graduated, I swore I never wanted to have anything to do with functional programming ever again, until a few of my coworkers started talking about languages like F#, Scala and Clojure last year. I have tried to avoid it for as long as I can, but it has proven inevitable.

In starting to read and play with Clojure, I have had to learn a lot of basic concepts that I might or might not have known before. I will attempt to highlight those concepts as I stumble upon them and illustrate them with code snippets that I find or ones that I wrote myself. Pardon the juvenile approach, I find I remember things better if I write them down or explain it to someone.

Lexical Scoping - with lexical or static scope, a variable always refers to its top-level environment. You can always determine a value of a variable based on just reading the code, substituting variable bindings as you go. Of course most programming languages work this way, I just never knew there was a term for it.

Here's some code (taken from this Clojure tutorial by R. Mark Volkmann) that illustrates lexical scoping and the usages of def, let and binding.

(def v 1) ; v is a global binding

(defn f1 []
  (println "f1: v =" v))

(defn f2 []
  (println "f2: before let v =" v)
  (let [v 2]
    (println "f2: in let, v =" v)
    (f1))
  (println "f2: after let v =" v))

(defn f3 []
  (println "f3: before binding v =" v)
  (binding [v 3]
    (println "f3: in binding, v =" v)
    (f1))
  (println "f3: after binding v =" v))

(defn f4 []
 (def v 4))

Calling f2 spits out the following output:


f2: before let v = 1
f2: in let, v = 2
f1: v = 1
f2: after let v = 1

The value of v is 2 only within the let form, and functions that are called within the body cannot see the local bindings of let.

Calling f3:


f3: before binding v = 1
f3: in binding, v = 3
f1: v = 3
f3: after binding v = 1

The binding macro is similar to let, but it creates thread-local values temporarily for existing global bindings. These new values are seen within the form and the functions that are called from within that form.

Calling f4: (println "after calling f4, v =" v):
after calling f4, v = 4

This actually changes the value of the global binding. Now calling f2 and f3 will have the following output:


f2: before let v = 4
f2: in let, v = 2
f1: v = 4
f2: after let v = 4
nil
f3: before binding v = 4
f3: in binding, v = 3
f1: v = 3
f3: after binding v = 4
nil