22
Clojure 4 Sequences Mar 25, 2 022

Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Embed Size (px)

Citation preview

Page 1: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Clojure 4

Sequences

Apr 20, 2023

Page 2: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Clojure errors (NO_SOURCE_FILE:12)

Useless--just means you’re running from the REPL shell

java.lang.Exception: EOF while reading (test.clj:139)

You have an unclosed parenthesis somewhere Use a good text editor! In jEdit, Control-A Control-I will make the error obvious

user=> (map (fn[x] (x * x)) (take 10 (iterate inc 1)))

java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

Page 3: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Sequences

In Clojure, almost every collection is a sequence user=> (cons 5 [1 2 3])(5 1 2 3) ; Not [5 1 2 3]

user=> (class '(1 2 3))clojure.lang.PersistentList

user=> (class [1 2 3])clojure.lang.LazilyPersistentVector

user=> (class (cons 5 [1 2 3]))clojure.lang.Cons

user=> (class (rest (cons 5 [1 2 3])))clojure.lang.LazilyPersistentVector$ChunkedSeq

Most common operations apply to all kinds of sequences If necessary, use the seq function to convert any sequence to a seq

Page 4: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Persistence and laziness

In Functional Programming, a persistent data structure is one that is itself immutable, but can be modified to create a “new” data structure The original and the new data structure share structure to

minimize copying time and wasted storage

A lazy data structure is one where parts of it do not exist until they are accessed This allows you to have “infinite” data structures

Page 5: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

range, take, and drop user=> (range 10)

(0 1 2 3 4 5 6 7 8 9) user=> (range 1 10)

(1 2 3 4 5 6 7 8 9) user=> (range 0 20 3)

(0 3 6 9 12 15 18)

user=> (range 10 20)(10 11 12 13 14 15 16 17 18 19)

user=> (take 4 (range 10 20))(10 11 12 13)

user=> (drop 4 (range 10 20))(14 15 16 17 18 19)

user=> (range 1 10)(1 2 3 4 5 6 7 8 9)

user=> (take 20 (range 1 10))(1 2 3 4 5 6 7 8 9)

user=> (drop 20 (range 1 10))()

user=> (take 4 "abcdefg")(\a \b \c \d)

user=> (str (take 4 "abcdefg"))"clojure.lang.LazySeq@3babc3"

user=> (apply str (take 4 "abcdefg"))"abcd"

Page 6: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

iterate iterate takes a function f and a starting value n, and lazily produces the

infinite series (n, f(n), f(f(n)), f(f(f(n))), ...)

; Don’t try this!user=> (iterate inc 1)(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...)

; But this is okayuser=> (take 5 (iterate inc 1))(1 2 3 4 5)

; Don’t try this!user=> (drop 5 (iterate inc 1))(6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21...)

; But this is okayuser=> (take 5 (drop 1000 (iterate inc 1)))(1001 1002 1003 1004 1005)

Page 7: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Fun with iterate user=> (take 10 (iterate (fn [x] (* 2 x)) 2))

(2 4 8 16 32 64 128 256 512 1024)

(defn collatz-1 [n] (cond (= n 1) 1 (even? n) (/ n 2) (odd? n) (inc (* 3 n)) ) )

user=> (take 5 (iterate collatz-1 7))(7 22 11 34 17)

user=> (take 25 (iterate collatz-1 7))(7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 1 1 1 1 1 1 1 1)

user=> (nth (iterate collatz-1 7) 4)17

Page 8: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Fibonacci numbers

user=> (defn next-pair [pair] (list (second pair) (+ (first pair) (second pair))))#'user/next-pair

user=> (next-pair '(1 1))(1 2)

user=> (next-pair '(1 2))(2 3)

user=> (take 10 (iterate next-pair '(0 1)))((0 1) (1 1) (1 2) (2 3) (3 5) (5 8) (8 13) (13 21) (21 34) (34 55))

user=> (map second (take 10 (iterate next-pair '(0 1))))(1 1 2 3 5 8 13 21 34 55)

Page 9: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Prime numbers user=> (defn divides [d n] (integer? (/ n d)))

#'user/divides user=> (divides 4 24)

true user=> (divides 5 24)

false

user=> (defn prime [n] (not-any? (fn [d] (divides d n)) (range 2 (dec n)))) #'user/prime

user=> (take 20 (filter prime (iterate inc 2)))(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71)

user=> (defn composite [n] (some (fn [d] (divides d n)) (range 2 (dec n)))) #'user/composite

user=> (take 20 (filter composite (iterate inc 1)))(4 6 8 9 10 12 14 15 16 18 20 21 22 24 25 26 27 28 30 32)

Page 10: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

let and letfn user=> (defn hypotenuse [a b] (let [a2 (* a a) b2 (* b b)]

(Math/sqrt (+ a2 b2)) ) ) #'user/hypotenuse

user=> (hypotenuse 3 4)5.0

user=> (hypotenuse 1 1)1.4142135623730951

user=> (defn hypotenuse [a b] (letfn [(square [n] (* n n))] (Math/sqrt (+ (square a) (square b)))))#'user/hypotenuse

user=> (hypotenuse 3 4)5.0

user=> (hypotenuse 1 1) 1.4142135623730951

Page 11: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Debugging with do user=> (format "%d + %d is %d\n" 3 4 7)

"3 + 4 is 7\n"

user=> (print (format "%d + %d is %d\n" 3 4 7))3 + 4 is 7nil

user=> (defn hypotenuse [a b] (letfn [(square [n] (* n n))] (do (println (format "a = %d, b = %d" a b)) (Math/sqrt (+ (square a) (square b))) ) ) ) #'user/hypotenuse

user=> (hypotenuse 3 4) a = 3, b = 4 5.0

Page 12: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

List comprehensions I for

macro

Usage: (for seq-exprs body-expr)

List comprehension. Takes a vector of one or more binding-form/collection-expr pairs, each followed by zero or more modifiers, and yields a lazy sequence of evaluations of expr.

Collections are iterated in a nested fashion, rightmost fastest, and nested coll-exprs can refer to bindings created in prior binding-forms.

Supported modifiers are::let [binding-form expr ...], :while test, :when test.

user=> (take 12 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y])) ([1 0] [2 0] [2 1] [3 0] [3 1] [3 2] [4 0] [4 1] [4 2] [4 3] [5 0] [5 1])

Source: http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/for

Page 13: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

List comprehensions II user=> (map (fn[x] (* x x)) (take 10 (iterate inc

1)))(1 4 9 16 25 36 49 64 81 100)

user=> (for [x (take 10 (iterate inc 1))] (* x x))(1 4 9 16 25 36 49 64 81 100)

user=> (take 10 (for [x (iterate inc 1)] (* x x)))(1 4 9 16 25 36 49 64 81 100)

user=> (for [x (iterate inc 1) :while (< x 11)] (* x x))(1 4 9 16 25 36 49 64 81 100)

user=> (for [x (range 1 11)] (* x x))(1 4 9 16 25 36 49 64 81 100)

Page 14: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

List comprehensions III user=> (for [x (range 1 11) :when (even? x)] (* x x))

(4 16 36 64 100)

user=> (take 10 (for [x (iterate inc 1) :when (even? x)] (* x x)))(4 16 36 64 100 144 196 256 324 400)

; Don't do this:user=> (for [x (iterate inc 1) :when (even? x)] (* x x))(4 16 36 64 100 144 196 256 324 400 484 576 676 784 ...

user=> (for [x "abcde" y [1 2]] [x y]) ([\a 1] [\a 2] [\b 1] [\b 2] [\c 1] [\c 2] [\d 1] [\d 2] [\e 1] [\e 2])

user=> (for [word ["the" "quick" "brown" "fox" "jumps"]] (format "Word: %s" word) )("Word: the" "Word: quick" "Word: brown" "Word: fox" "Word: jumps")

Page 15: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Partial functions

(partial f arg1 arg2 arg3 & more)Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variable number of additional args. When called, the returned function calls f with args + additional args.

user=> (def hundred-times (partial * 100))#'user/hundred-times

user=> (hundred-times 5)500

Page 16: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Prime, revisited user=> (defn prime [n]

(not-any? (fn [d] (divides d n)) (range 2 (dec n))))#'user/prime

user=> (defn divisible [n d] (integer? (/ n d)))#'user/divisible

user=> (divisible 24 3)true

user=> (divisible 24 5)false

user=> (defn prime [n] (not-any? (partial divisible n) (range 2 (dec n))))#'user/prime

user=> (prime 21)false

user=> (prime 19)true

Page 17: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Member user=> (defn member [e coll]

(cond (empty? coll) false (= e (first coll)) true :else (member e (rest coll)) ) )#'user/member

user=> (member 5 (range 1 10))true

user=> (member 5 (range 10 20))false

Page 18: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Member, revisited user=> (some (partial = 5) (range 1 10))

true

user=> (some (partial = 5) (range 10 20))nil

user=> (defn member [e coll] (some (partial = e) coll))#'user/member

user=> (member 5 (range 1 10))true

user=> (member 5 (range 10 20))nil

Page 19: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Avoiding recursion

Java is an object-oriented language You have a lot of classes available to you You should not write your own Stack class!

Clojure is a very recursive language There are a lot of built-in functions that are recursive You should avoid recursion if Clojure will do it for you

Page 20: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Zip (defn zip [a b]

(if (or (empty? a) (empty? b)) () (cons (list (first a) (first b)) (zip (rest a) (rest b))) ) )

user=> (zip [1 2 3 4] [:a :b :c])((1 :a) (2 :b) (3 :c))

user=> (zip '(1 2 3 4) '(:a :b :c))((1 :a) (2 :b) (3 :c))

user=> (def zip4 (partial zip [1 2 3 4]))#'user/zip4

user=> (zip4 "abcde")((1 \a) (2 \b) (3 \c) (4 \d))

Page 21: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

Best reference

http://clojure.github.com/clojure/clojure.core-api.html

Page 22: Clojure 4 Sequences 20-Oct-15. Clojure errors (NO_SOURCE_FILE:12) Useless--just means you’re running from the REPL shell java.lang.Exception: EOF while

The End