diff options
author | Rich Hickey <richhickey@gmail.com> | 2009-01-30 01:11:09 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2009-01-30 01:11:09 +0000 |
commit | ca1765e542a2c668512f67b99ef1e50c4b1b313e (patch) | |
tree | 90aad9ecc4d5b3fc355818bd2d28f83582c5f832 /src | |
parent | 42715f9d8ab764a89e3f69cd2c508901a24fc881 (diff) |
[lazy] added more, made filter and map use lazy-seq, made Delay.Seq implement IPersistentCollection and List
Diffstat (limited to 'src')
-rw-r--r-- | src/clj/clojure/core.clj | 55 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Delay.java | 202 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 18 |
3 files changed, 235 insertions, 40 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 2cf79beb..d95e3972 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -48,6 +48,12 @@ rest (fn rest [x] (. clojure.lang.RT (rest x)))) (def + #^{:arglists '([coll]) + :doc "Returns a seqable collection of the items after the first. May return nil. Calls seq on its + argument."} + more (fn more [x] (. clojure.lang.RT (more x)))) + +(def #^{:arglists '([coll x] [coll x & xs]) :doc "conj[oin]. Returns a new collection with the xs 'added'. (conj nil item) returns (item). The 'addition' may @@ -418,6 +424,16 @@ (cat (concat x y) zs)))) ;;;;;;;;;;;;;;;;at this point all the support for syntax-quote exists;;;;;;;;;;;;;;;;;;;;;; + +(defmacro lazy-seq + "Takes a body of expressions that returns an ISeq or nil, and yields + a Seqable object that will invoke the body only the first time seq + is called, and will cache the result and return it on all subsequent + seq calls. Any closed over locals will be cleared prior to the tail + call of body." + [& body] + (list 'new 'clojure.lang.Delay$Seq (list* `#^{:once true} fn* [] body))) + (defmacro delay "Takes a body of expressions and yields a Delay object that will invoke the body only the first time it is forced (with force), and @@ -1393,26 +1409,30 @@ not-any? (comp not some)) (defn map - "Returns a lazy seq consisting of the result of applying f to the + "Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments." ([f coll] - (when (seq coll) - (lazy-cons (f (first coll)) (map f (rest coll))))) + (lazy-seq + (when (seq coll) + (cons (f (first coll)) (map f (more coll)))))) ([f c1 c2] - (when (and (seq c1) (seq c2)) - (lazy-cons (f (first c1) (first c2)) - (map f (rest c1) (rest c2))))) + (lazy-seq + (when (and (seq c1) (seq c2)) + (cons (f (first c1) (first c2)) + (map f (more c1) (more c2)))))) ([f c1 c2 c3] - (when (and (seq c1) (seq c2) (seq c3)) - (lazy-cons (f (first c1) (first c2) (first c3)) - (map f (rest c1) (rest c2) (rest c3))))) + (lazy-seq + (when (and (seq c1) (seq c2) (seq c3)) + (cons (f (first c1) (first c2) (first c3)) + (map f (more c1) (more c2) (more c3)))))) ([f c1 c2 c3 & colls] (let [step (fn step [cs] - (when (every? seq cs) - (lazy-cons (map first cs) (step (map rest cs)))))] + (lazy-seq + (when (every? seq cs) + (cons (map first cs) (step (map more cs))))))] (map #(apply f %) (step (conj colls c3 c2 c1)))))) (defn mapcat @@ -1422,13 +1442,16 @@ (apply concat (apply map f colls))) (defn filter - "Returns a lazy seq of the items in coll for which + "Returns a lazy sequence of the items in coll for which (pred item) returns true. pred must be free of side-effects." [pred coll] - (when (seq coll) - (if (pred (first coll)) - (lazy-cons (first coll) (filter pred (rest coll))) - (recur pred (rest coll))))) + (let [step (fn [pred coll] + (when (seq coll) + (if (pred (first coll)) + (clojure.lang.Cons. (first coll) (filter pred (more coll))) + (recur pred (more coll)))))] + (lazy-seq (step pred coll)))) + (defn remove "Returns a lazy seq of the items in coll for which diff --git a/src/jvm/clojure/lang/Delay.java b/src/jvm/clojure/lang/Delay.java index eed98fd0..83e58a37 100644 --- a/src/jvm/clojure/lang/Delay.java +++ b/src/jvm/clojure/lang/Delay.java @@ -12,31 +12,33 @@ package clojure.lang; -public class Delay{ -Object val; -IFn fn; +import java.util.*; -public Delay(IFn fn){ - this.fn = fn; - this.val = null; -} +public class Delay { + Object val; + IFn fn; -static public Object force(Object x) throws Exception{ - return (x instanceof Delay) ? - ((Delay) x).get() - : x; -} + public Delay(IFn fn) { + this.fn = fn; + this.val = null; + } -synchronized Object get() throws Exception{ - if(fn != null) - { - val = fn.invoke(); - fn = null; - } - return val; -} + static public Object force(Object x) throws Exception { + return (x instanceof Delay) ? + ((Delay) x).get() + : x; + } - static public class Seq extends Delay implements Seqable{ + synchronized Object get() throws Exception { + if (fn != null) + { + val = fn.invoke(); + fn = null; + } + return val; + } + + static public class Seq extends Delay implements IPersistentCollection, List { public Seq(IFn fn) { super(fn); } @@ -51,5 +53,163 @@ synchronized Object get() throws Exception{ throw new RuntimeException(e); } } + + public int count() { + int c = 0; + for (ISeq s = seq(); s != null; s = s.rest()) + ++c; + return c; + } + + public IPersistentCollection cons(Object o) { + return RT.cons(o, seq()); + } + + public IPersistentCollection empty() { + return null; + } + + public boolean equiv(Object o) { + ISeq s = seq(); + return s == o || (s != null && s.equiv(o)); + } + + public int hashCode() { + return Util.hash(seq()); + } + + public boolean equals(Object o) { + ISeq s = seq(); + return s == o || (s != null && s.equals(o)); + } + + +// java.util.Collection implementation + + public Object[] toArray() { + return RT.seqToArray(seq()); + } + + public boolean add(Object o) { + throw new UnsupportedOperationException(); + } + + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + public boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public boolean containsAll(Collection c) { + for (Object o : c) + { + if (!contains(o)) + return false; + } + return true; + } + + public Object[] toArray(Object[] a) { + if (a.length >= count()) + { + ISeq s = seq(); + for (int i = 0; s != null; ++i, s = s.rest()) + { + a[i] = s.first(); + } + if (a.length > count()) + a[count()] = null; + return a; + } + else + return toArray(); + } + + public int size() { + return count(); + } + + public boolean isEmpty() { + return count() == 0; + } + + public boolean contains(Object o) { + for (ISeq s = seq(); s != null; s = s.rest()) + { + if (Util.equiv(s.first(), o)) + return true; + } + return false; + } + + public Iterator iterator() { + return new SeqIterator(seq()); + } + + //////////// List stuff ///////////////// + private List reify() { + return new ArrayList(this); + } + + public List subList(int fromIndex, int toIndex) { + return reify().subList(fromIndex, toIndex); + } + + public Object set(int index, Object element) { + throw new UnsupportedOperationException(); + } + + public Object remove(int index) { + throw new UnsupportedOperationException(); + } + + public int indexOf(Object o) { + ISeq s = seq(); + for (int i = 0; s != null; s = s.rest(), i++) + { + if (Util.equiv(s.first(), o)) + return i; + } + return -1; + } + + public int lastIndexOf(Object o) { + return reify().lastIndexOf(o); + } + + public ListIterator listIterator() { + return reify().listIterator(); + } + + public ListIterator listIterator(int index) { + return reify().listIterator(index); + } + + public Object get(int index) { + return RT.nth(this, index); + } + + public void add(int index, Object element) { + throw new UnsupportedOperationException(); + } + + public boolean addAll(int index, Collection c) { + throw new UnsupportedOperationException(); + } + } } diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 8e3a7fab..9ec66cae 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -528,10 +528,13 @@ static public IPersistentCollection conj(IPersistentCollection coll, Object x){ } static public ISeq cons(Object x, Object coll){ - ISeq y = seq(coll); - if(y == null) + //ISeq y = seq(coll); + if(coll == null) return new PersistentList(x); - return y.cons(x); + else if (coll instanceof Seqable) + return new Cons(x, (Seqable) coll); + else + return new Cons(x, seq(coll)); } static public Object first(Object x){ @@ -564,6 +567,15 @@ static public ISeq rest(Object x){ return seq.rest(); } +static public Seqable more(Object x){ + if(x instanceof ISeq) + return ((ISeq) x).more(); + ISeq seq = seq(x); + if(seq == null) + return null; + return seq.more(); +} + static public ISeq rrest(Object x){ return rest(rest(x)); } |