This Clojure Firehose

Previously, I've been starting my foray into Clojure-land with some pretty basic stuff, an intro to some datastructures. Now I'm going into more interesting territory: functions, namespaces, blocks & scope.

Functions make the Lisp go round

Functions Anonymous

Defining anonymous functions is done with this 'special form' ie. builtin primitive:

user> (fn [a] (+ a 1))
#<user$eval913$fn__914 user$eval913$fn__914@61ade7f6>

That's the internal name of an anonymous fun. Define and call it in one go:

user> ((fn [a] (+ a 1)) 3)
4

Or bind it to a var:

user> (def f (fn [a] (+ a 1)))
#'user/f
user> (f 4)
5

There's a macro to create named functions though, and you can also pass in a docstring:

user> (defn g "The g func" [a b] (* a b))
#'user/g
user> (g 0 1)
0

Much more convenient of course.

Multiple Arieties, VarArgs

Like Erlang, Clojure supports functions with multiple arietes. I think I like Clojures' syntax better though:

user> (defn f
        ([a]
           (f a 2))
        ([a b]
           (* a b)))
#'user/f
user> (f 2)
4
user> (f 2 3)
6

That feels pretty clean.

There's syntax to support varargs (optional arguments) as well. With a wrong number of args you'd get:

user> (f)
ArityException Wrong number of args (0)...

For varargs, put an & after fixed args:

user> (defn h [a & moar] {a moar})
#'user/h

Optional arguments are passed in as a list:

user> (h 0 :a :b :c)
{0 (:a :b :c)}

If they're ommitted, the list is nil:

user> (h 1)
{1 nil}

We defined h to expect at least one argument though. When called without any arg, we still get a ArityException, as it should be:

user> (h)
ArityException ...

The idiom to destructure varargs is similar to Erlangs', ie. individual positional parameters can be placed in a vector:

user> (defn h [& [one two]] (str one two))
#'user/h
user> (h 1 2)
"12"
user> (h)
""

Reader Features and Inplace Functions

"Reader features" are basically Clojure terminology for a pre-processor with a set of predefined templates.

One of these is the in-place function. An in-place function is a shorthand for the anonymous function above, writing #(...) instead of (fn ...) and numbered args (where %1 is the first, %2 the seconded etc.). Defining a function to add 23 and calling it is:

user> (#( + %1 23) 2)
25

Locals, Loops, And Blocks

Blocks

Group several expressions with a do block. Useful in cases where syntactically only one expression is allowed, but more are needed for sideeffects:

user> (do (def a 2) (def b 5) (* a b))
10

Locals

You can perform local bindings with the (let ) form. Inside the parens, the bindings are effective and immutable.

user> (let [a 23]
        (def a "cat")
        (- a 1))
22

But a nested binding would shadow a binding in an outer scope:

user> (let [a 23]
        (+ a 1)
        (let [a "cat"] a))
"cat"

Loops, Recursive: see Recursive

I was wondering about the "recur" form -- why not just use recursion instead of bothering the user with a special case? Until it dawned on me that the JVM probably would have to support tail call optimization, which indeed it does not. TJoC opines that "recursion from a tail position is in many ways like a structured goto" -- quite so. But then again, it's maybe a good thing to have a specific form for tail calls so as to make more transparent what is going on.

user> (defn su [a]
(loop [sum 0, a1 a]
  (if (seq a1)
    (recur (+ sum (first a1)) (rest a1))
    sum)))
#'user/su
user> (su [1 2])
3
user> (reduce + [1 2])
3

Mordac The Preventer (Quoting)

To prevent evaluation of collections they can be quoted. Classical Lisp hat the quote fun, respectively the single-quote shorthand:

user> '(+ 1 2)
(+ 1 2)

Syntax-quoting is a variant for Clojure that has some extra features, namely auto-qualification:

user> `(+ 1 2)
(clojure.core/+ 1 2)

This can be handy I guess when persisting code across namespaces.

If some of the expression that you're syntax-quoting should exempted from the quote, ie. should be evaluated right away, there's the unquote form:

user> `(1 2 ~(+ 3 4))
(1 2 7)

To splice contents of a list into another without quoting, use the unquote-splice form ~@

user> (let [x '(2 3)] `(1 ~@x))
(1 2 3)

Automatically construct a uniqe symbol:

user> `sym#
sym__699__auto__

Java (and others) Interop

Static class members access:

user> java.lang.Long/MAX_VALUE
9223372036854775807

Objects can be constructed with ClassName., and methods are accessed with funcalls of the form (.method object [args]).

Create a Java HashMap instance with keys "foo" and "bar, retrieve the value of "foo", update "foo" and retrieve again:

user> (def h (java.util.HashMap. {"foo" 23 "bar" 42}))
#'user/h
user> (.get h "foo")
23
user> (.put h "foo" "quux")
23
user> (.get h "foo")
"quux"

The .. macro is convenience for chained method calls. Eg. for Java code like:

// java
h.get("foo").endsWith("ux");

you can conveniently use:

user> (.. h (get "foo") (endsWith "ux"))
true

The doto macro bundles a set of mutators and an object:

user> (doto h
        (.put "foo" 77)
        (.put "fuxor" "niyah"))

Anomalies

This is pretty directly taken over from Java, except there's no checked exception requirement, thank god.

Throwing:

user> (throw (Exception. "nooo!"))
Exception nooo!...

Catching:

user> (try (#(/ 1 0 ))
           (catch
               ArithmeticException
               e "beware the singularity"))
"beware the singularity"

Spaces

Namespaces are Clojures' way of modularizing code. You can declare a new namespace with the ns form. Any var created in a namespace is local to that namespace, as you'd expect. There's a handy built-in var *ns* that refers to the current namespace.

We're making a new namespace:

user> (ns foo.bar)
nil
foo.bar> *ns*
#<Namespace foo.bar>

The var x is local to foo.bar:

foo.bar> (def x 23)
#'foo.bar/x
foo.bar> (ns foo.quux)
nil
foo.quux> x
CompilerException java.lang.RuntimeException: Unable to resolve symbol: x ...

But we can refer to it with a fully qualified name:

foo.quux> foo.bar/x
23

And we can switch back as well:

foo.quux> (ns foo.bar)
nil
foo.bar> x
23

Works with funs as well:

foo.bar> (defn f [a] (* a a))
#'foo.bar/f
foo.bar> (f 2)
4
foo.bar> (ns foo.quux)
nil
foo.quux> f
CompilerException java.lang.RuntimeException: Unable to
resolve symbol: f ...
foo.quux> (foo.bar/f 4)
16

Loading Namespaces

Declaring a namespace and loading another library with an alias:

peter> (ns peter (:require [clojure.string :as st]))
nil
peter> (st/split-lines "foo \n bar")
["foo " " bar"]

Using a specific function from another library:

peter> (ns peter (:require [clojure.java.shell :refer (sh)]))
nil
peter> (sh "hostname" "-s")
{:exit 0, :out "newton\n", :err ""}

Wrapping

This part started with functions, then touched reader features, scoping, quoting, Java interop, and namespaces. Quite intense. By now I think I might actually be able to DO something with Clojure.

 · 
peter
 ·