Download presentation
1
Clojure 2 Feb 7, 2015 1
2
2
3
Functions The syntax to define a named function is: (defn function_name [arguments] expressions) The value of the function is the value of the last expression evaluated The syntax of a function call is (function arguments) Notice that the function being called is the first thing inside the parentheses This need not be the name of a function; it can be any expression that results in a function 3
4
Tail recursion (Erlang)
Non-tail recursive function to find the length of a list: len([]) -> 0; len([_ | T]) -> 1 + len(T). Tail recursive function to find the length of a list: len(L) -> len(0, L). len(N, []) -> N; len(N, [_ | T]) -> len(N + 1, T). 4
5
Tail recursion (Clojure)
Non-tail recursive function to find the length of a list: (defn len-1 [lst] (if (empty? lst) (inc (len-1 (rest lst))) ) ) Tail recursive function to find the length of a list: (defn len ([lst] (len-2 0 lst)) ([n lst] (if (empty? lst) n (len-2 (inc n) (rest lst))) ) ) 5
6
recur The previous function, len-2, is tail-recursive, but the compiler doesn’t optimize it into a loop Clojure runs on the JVM, which doesn’t optimize tail recursion Workaround: (defn len ([lst] (len-2 0 lst)) ([n lst] (if (empty? lst) n (recur (inc n) (rest lst))) ) ) 6
7
Tail recursion (Erlang)
Non-tail recursive function to find the factorial: factorial(1) -> 1; factorial(N) -> N * factorial(N - 1). Tail recursive function to find the factorial: factorial(N) -> factorial(1, N). factorial(Acc, 1) -> Acc; factorial(Acc, N) -> factorial(N * Acc, N - 1). 7
8
Tail recursion (Clojure)
Non-tail recursive function to find the factorial: (defn factorial-1 [n] (if (= n 1) (* n (factorial-1 (dec n))) ) Tail recursive function to find the factorial: (defn factorial ([n] (factorial-2 1 n)) ([acc n] (if (= n 1) acc (recur (* n acc) (dec n)) ) ) ) 8
9
Loop version of factorial
(def factorial (fn [n] (loop [cnt n acc 1] (if (zero? cnt) acc (recur (dec cnt) (* acc cnt))))))
10
Lists vs. vectors Lists uses (a b c) syntax, vectors use [a b c]
Lists do standard Lisp evaluation (evaluate arguments, then apply function in first position to them). Vectors evaluate to themselves. Lists use the cons cell representation we have seen. Vectors use an internal representation that more efficiently supports extension.
11
Lists vs. vectors (continued)
(def mylist '(a b c d)) user=> (cons 'q mylist) (q a b c d) ;; but mylist is unchanged (def myvec [a b c d]) user=> (conj myvec 'q) [a b c d q] ;; but myvec is unchanged
12
Vectors as stacks (def mystack [1 2 3]) user=> (peek mystack) 3
user=> (pop mystack) [1 2] ;; but mystack is unchanged user=> (conj mystack 4) [ ] ;; but mystack is still unchanged
13
map (def fruit '((apple red) (banana yellow) (cherry red)))
user=> (map first fruit) (apple banana cherry) (defn my-map [f lst] (if (empty? lst) () (cons (f (first lst)) (my-map f (rest lst))) ) ) user=> (map my-first fruit) (apple banana cherry) 13
14
Map using tail recursion
(defn strict-map1 [f coll] (loop [coll coll, acc nil] (if (empty? Coll) (reverse acc) (recur (next coll) (cons (f (first coll)) acc)))))
15
Map using vectors (defn strict-map2 [f coll] (loop [coll coll, acc []]
(if (empty? Coll) acc (recur (next coll) (conj acc (f (first coll))))))
16
Conj vs. cons The “right” way to add an element to any sequence in Clojure is conj. It always adds elements in the most efficient way. (cons 1 '(2 3)) => (1 2 3) (conj '(2 3) 1) => (1 2 3) (conj [2 3] 1) => [2 3 1]
17
Anonymous functions An anonymous function has the syntax: (fn [parameters] body) Example: (fn [x] (* x x)) 17
18
filter (def fruit '((apple red) (banana yellow) (cherry red)))
user=> (filter (fn [x] (= (second x) 'red)) fruit) ((apple red) (cherry red)) (defn my-filter [p lst] (cond (empty? lst) () (p (first lst)) (cons (first lst) (my-filter p (rest lst))) :else (my-filter p (rest lst)) ) ) user=> (my-filter (fn [x] (= (second x) 'red)) fruit) ((apple red) (cherry red)) 18
19
Speaking of maps… A map or hash is a sequence of key/value pairs, enclosed in braces, for example, {:ace 1, :deuce 2, "trey" 3} Elements are separated by whitespace or commas It is helpful to use commas between key/value pairs A map is also a function: user=> (def cards {:ace 1, :deuce 2, "trey" 3}) #'user/cards user=> (cards :deuce) 2 Keywords are also functions: user=> (:deuce cards) 2 19
20
Immutability and Laziness
Two key ideas in Clojure. Immutable objects never change once they are created. Why would Clojure do this? Invariants can be handled just at construction time. Reasoning about possible states is simplified. Equality has persistent meaning. Sharing is cheap. Just send a reference. Fosters concurrent programming.
21
Structural Sharing (def baselist (list :barnabas :adam))
(def lst1 (cons :willie baselist)) (def lst2 (cons :phoenix baselist)) (= (next lst1) (next lst2)) ; true (identical? (next lst1) (next lst2)) ;; also true
22
Simple tree example Demonstrates more complex structural sharing.
xconj from pgs in Joy
23
The End
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.