CSci 1301: Clojure examples

Running Clojure

Clojure is a functional programming language with support for parallel computation.

To run clojure, download the latest version (as a .zip file) and unpack it. To run it, start a command prompt, navigate to the directory where Clojure is unpacked using cd command, for instance:


cd Desktop\1301_fall09\clojure_1.0.0

Then run it by typing


java -cp clojure-1.0.0.jar clojure.lang.Repl

where clojure-1.0.0.jar is the name of the .jar file in the downloaded Clojure folder.

Clojure sample code


(+ 1 2 3) ; just like Scheme

;; function definition 
(defn average [x y] (/ (+ x y) 2))

;; function call
(average 2 5)

;; a function that returns a function
(defn addx [x] (fn [y] (+ x y)))

;; using a map to add 5 to all elements of a list
;; recall the quote notation for lists
(map (addx 5) '(1 2 3 4 5))

;; expected value:
'(6 7 8 9 10)

;; passing a "lambda" (anonymous) function to map
;; %1 means "the first argument"; you can have %2, %3, etc.
(map #(+ %1 5) '(1 2 3 4 5))

;; structures are called "maps" in Clojure and have
;; a different syntax:

;; a "structure" with a name and a gpa fields
;; terminology: :name is a key, 'Sally is a value 

;; a structure created "on the fly"
(def Sally {:name 'SallySmith :gpa 3.0})
(:name Sally) ; selector
(:gpa Sally)  ; selector

;; defining a structure type (struct in Scheme)
(defstruct student :name :gpa)
(struct-map student :name 'BobBrown :gpa 2.9)

nil ;; a value that represents an empty list; also means "false" in cond

;; strings are Java string; you can call Java methods on them
;; in Java you would write mystring.split(), mystring.toUpperCase
(map (fn [x] (.toUpperCase x)) (.split "Dasher Dancer Prancer" " "))

;; functions of varying number of arguments
(def min12 (fn ([x] x) 
               ([x y] (if (< x y) x y))
))
(min12 4)
(min12 2 3)

;; Examples from
;; http://en.wikibooks.org/wiki/Clojure_Programming/By_Example

;; there is a special construct for tail recursion: recur
(defn factorial [n]
  (defn fac [n acc]
    (if (zero? n)
       acc
      (recur (- n 1) (* acc n)))) ; recursive call to fac, 
      ; but reuses the stack; n will be (- n 1), and acc will be (* acc n)
  (fac n 1))

;; loops are written using recur
(loop [cnt 5 acc 1]
  (if (zero? cnt)
    acc
    (recur (dec cnt) (* acc cnt))))

;;;; Concurrency (parallel programming)
;; Clojure uses Java threads. It provides different types of shared
;; mutable data and operations for modifying these data in a safe way 

;; The three types are: refs (references), agents, and atoms

;; Refs are shared among threads and are modified in a transaction.
;; A transaction is an all-or-nothing sequence of steps: either all
;; steps are done with the exclusive ownership of the data, or none 
;; are done, and the transaction will retry later.
;; More here:
;; http://clojure.org/refs

;; define a reference r with a value 6
(def r (ref 6))

;; an update must be done in a transaction "dosync"
(dosync (ref-set r 5))

;; get the value in r
@r

;; Agents: asynchronous safe modification
;; Unlike refs, where the thread will wait for dosync to finish,
;; an agent sends a request for a modification, and the program 
;; continues. 
;; Functions that modify an agent are queued and execute one at a 
;; time when the agent becomes available.

;; define an agent "a" with a value 1
(def a (agent 1))

;; "send" an increment request to a (add 1 to a)
(send a inc)

;; wait for all requests to a (at the time of await) to finish
(await a)

;; get the value in a
@a

;; Atoms are modified in a synchronous manner, i.e. a thread with a 
;; request to change an atom will wait for the function to return.
;; A request for change is applied without "locking" the atom. 
;; If another thread has changed the atom after the modifying function 
;; started and before it returned then the function is retried. 
;; Therefore functions applied to atoms cannot have side affects
;; on anything other than the atom itself

;; define an atom atm with a value 1
(def atm (atom 1))

;; swap! is sending an increment request to atm
(swap! atm inc)

;; get the value of the atom
@atm

CSci 1301 course web site.