diff options
author | Rich Hickey <richhickey@gmail.com> | 2007-09-27 01:41:35 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2007-09-27 01:41:35 +0000 |
commit | a255c8e8bc00b9adddd02c0e9714d862dacf8709 (patch) | |
tree | 544d89737d7712cf15ed0be6f5206f26b6c580f7 | |
parent | 95e04a8d55631a9e83f44f94a95a2ed527741faa (diff) |
more functional libs
-rw-r--r-- | clojure.markdown | 35 | ||||
-rw-r--r-- | src/boot.clj | 65 |
2 files changed, 75 insertions, 25 deletions
diff --git a/clojure.markdown b/clojure.markdown index 7dc9c489..febb898c 100644 --- a/clojure.markdown +++ b/clojure.markdown @@ -488,7 +488,7 @@ Conj[oin]. Returns a *new* collection with the item 'added'. `(conj nil item)` r --- ### (*seq* coll) -Sequence. Returns a new ISeq on the collection. If the collection is empty, returns `nil`. `(seq nil)` returns `nil`. +Sequence. Returns a new ISeq on the collection. If the collection is empty, returns `nil`. `(seq nil)` returns `nil`. `seq` also works on native Java arrays and any objects that implement Iterable. ### _Lists (IPersistentList)_ @@ -575,7 +575,13 @@ Returns a sequence of the map's values. <h2 id="sequences">Sequences</h2> -Clojure defines many algorithms in terms of sequences (seqs). A seq is a logical list, and where in most Lisps the list is represented by a concrete, 2-slot structure, Clojure uses the ISeq interface to allow many data structures to offer access to their elements as lists. The `seq` function yields an implementation of ISeq appropriate to the collection. Seqs differ from iterators in that they are immutable, not stateful cursors into a collection. As such, they are useful for much more than foreach - functions can consume and produce seqs, they are thread safe, they can share structure etc. +Clojure defines many algorithms in terms of sequences (seqs). A seq is a logical list, and where in most Lisps the list is represented by a concrete, 2-slot structure, Clojure uses the ISeq interface to allow many data structures to provide access to their elements as sequences. The `seq` function yields an implementation of ISeq appropriate to the collection. Seqs differ from iterators in that they are persistent and immutable, not stateful cursors into a collection. As such, they are useful for much more than foreach - functions can consume and produce seqs, they are thread safe, they can share structure etc. + +Most of the sequence library functions are *lazy*, i.e. functions that return seqs do so incrementally, as they are consumed, and thus consume any seq arguments incrementally as well. + +When `seq` is used on native Java arrays and objects that implement Iterable, the resulting sequence is still immutable and persistent, and will represent a single pass across the data. Because that pass might happen lazily, the pass might see changes that happen after `seq` has been called. Also, if the backing iterator is subject to ConcurrentModificationException, then so to is the resulting seq. That said, there is still a lot of utility to using seq on Iterables and arrays - since seqs support multi-pass and lazy algorithms. Robust programs should not mutate arrays or Iterables that have seqs on them. + +####The Seq interface: --- ### (*first* seq) @@ -589,6 +595,31 @@ Returns a seq of the items after the first. If there are no more items, returns ### (*cons* item coll) Returns a new seq where item is the first element and the sequence of items in coll is the rest of the seq. +####The Seq library: + +--- +### (every pred seq) +### (not-every pred seq) +### (any pred seq) +### (not-any pred seq) +### (concat seqs*) +### (map f seqs*) +### (mapcat f seqs*) +### (reduce f seq) +### (reduce f seq val) +### (filter pred seq) +### (take n seq) +### (take-while pred seq) +### (drop n seq) +### (drop-while pred seq) +### (reverse seq) +### (cycle seq) +### (split-at n seq) +### (split-with pred seq) +### (repeat x) +### (replicate n x) +### (iterate f x) + <h2 id="metadata">Metadata</h2> Symbols and collections support metadata, a map of data *about* the symbol or collection. The metadata system allows for arbitrary annotation of data. It is used to convey information to the compiler about types, but can also be used by application developers for many purposes, annotating data sources, policy etc. diff --git a/src/boot.clj b/src/boot.clj index 9beacf4c..d2e2e309 100644 --- a/src/boot.clj +++ b/src/boot.clj @@ -318,6 +318,25 @@ `(. clojure.lang.LockingTransaction (runInTransaction (fn [] ~@body)))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; fn stuff ;;;;;;;;;;;;;;;; +(defn comp [& fs] + (let [fs (reverse fs)] + (fn [& args] + (loop [ret (apply (first fs) args) fs (rest fs)] + (if fs + (recur ((first fs) ret) (rest fs)) + ret))))) + +(defn curry + ([f arg1] + (fn [& args] (apply f arg1 args))) + ([f arg1 arg2] + (fn [& args] (apply f arg1 arg2 args))) + ([f arg1 arg2 arg3] + (fn [& args] (apply f arg1 arg2 arg3 args))) + ([f arg1 arg2 arg3 & more] + (fn [& args] (apply f arg1 arg2 arg3 (concat more args))))) + ;;;;;;;;;;;;;;;;;;; sequence fns ;;;;;;;;;;;;;;;;;;;;;;; (defn every [pred coll] @@ -326,6 +345,14 @@ (recur pred (rest coll))) t)) +(def not-every (comp not every)) + +(defn any [pred coll] + (when (seq coll) + (or (pred (first coll)) (recur pred (rest coll))))) + +(def not-any (comp not any)) + (defn map ([f coll] (when (seq coll) @@ -335,6 +362,9 @@ (lazy-cons (apply f (first coll) (map first colls)) (apply map f (rest coll) (map rest colls)))))) +(defn mapcat [f & colls] + (apply concat (apply map f colls))) + (defn reduce ([f coll] (if (seq coll) @@ -345,15 +375,19 @@ (recur f (rest coll) (f val (first coll))) val))) +(defn filter [pred coll] + (when (seq coll) + (if (pred (first coll)) + (lazy-cons (first coll) (filter pred (rest coll))) + (recur pred (rest coll))))) + (defn take [n coll] (when (and (pos? n) (seq coll)) (lazy-cons (first coll) (take (dec n) (rest coll))))) (defn take-while [pred coll] - (when (seq coll) - (if (pred (first coll)) - (lazy-cons (first coll) (take-while pred (rest coll))) - (recur pred (rest coll))))) + (when (and (seq coll) (pred (first coll))) + (lazy-cons (first coll) (take-while pred (rest coll))))) (defn drop [n coll] (if (and (pos? n) (seq coll)) @@ -377,9 +411,12 @@ (when (seq coll) (cycle-rep (seq coll) (seq coll)))) -(defn split [n coll] +(defn split-at [n coll] [(take n coll) (drop n coll)]) +(defn split-with [pred coll] + [(take-while pred coll) (drop-while pred coll)]) + (defn repeat [x] (lazy-cons x (repeat x))) @@ -390,21 +427,3 @@ (let [v (f x)] (lazy-cons v (iterate f v)))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; fn stuff ;;;;;;;;;;;;;;;; -(defn comp [& fs] - (let [fs (reverse fs)] - (fn [& args] - (loop [ret (apply (first fs) args) fs (rest fs)] - (if fs - (recur ((first fs) ret) (rest fs)) - ret))))) - -(defn curry - ([f arg1] - (fn [& args] (apply f arg1 args))) - ([f arg1 arg2] - (fn [& args] (apply f arg1 arg2 args))) - ([f arg1 arg2 arg3] - (fn [& args] (apply f arg1 arg2 arg3 args))) - ([f arg1 arg2 arg3 & more] - (fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))
\ No newline at end of file |