1 / 23

Feb 7, 2015

Clojure 2. Feb 7, 2015. 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 )

Philip
Download Presentation

Feb 7, 2015

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Clojure 2 Feb 7, 2015

  2. 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(functionarguments) • 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

  3. 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. Tail recursion (Clojure) • Non-tail recursive function to find the length of a list:(defn len-1 [lst] (if (empty? lst) 0 (inc (len-1 (rest lst))) ) ) • Tail recursive function to find the length of a list:(defn len-2 ([lst] (len-2 0 lst)) ([n lst] (if (empty? lst) n (len-2 (inc n) (rest lst))) ) )

  5. 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-2 ([lst] (len-2 0 lst)) ([n lst] (if (empty? lst) n (recur (inc n) (rest lst))) ) )

  6. 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. Tail recursion (Clojure) • Non-tail recursive function to find the factorial:(defn factorial-1 [n] (if (= n 1) 1 (* n (factorial-1 (dec n))) ) • Tail recursive function to find the factorial:(defn factorial-2 ([n] (factorial-2 1 n)) ([acc n] (if (= n 1) acc (recur (* n acc) (dec n)) ) ) )

  8. Loop version of factorial • (def factorial • (fn [n] • (loop [cnt n acc 1] • (if (zero? cnt) • acc • (recur (dec cnt) (* acc cnt))))))

  9. 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.

  10. 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

  11. 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)[1 2 3 4] ;; but mystack is still unchanged

  12. 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. 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)))))

  14. Map using vectors (defn strict-map2 [f coll] (loop [coll coll, acc []] (if (empty? Coll) acc (recur (next coll) (conj acc (f (first coll))))))

  15. 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]

  16. Anonymous functions • An anonymous function has the syntax:(fn [parameters] body) • Example:(fn [x] (* x x))

  17. 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. 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. 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.

  20. 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

  21. Simple tree example Demonstrates more complex structural sharing. xconj from pgs. 120-123 in Joy

  22. The End

More Related