summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2009-01-30 01:11:09 +0000
committerRich Hickey <richhickey@gmail.com>2009-01-30 01:11:09 +0000
commitca1765e542a2c668512f67b99ef1e50c4b1b313e (patch)
tree90aad9ecc4d5b3fc355818bd2d28f83582c5f832 /src
parent42715f9d8ab764a89e3f69cd2c508901a24fc881 (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.clj55
-rw-r--r--src/jvm/clojure/lang/Delay.java202
-rw-r--r--src/jvm/clojure/lang/RT.java18
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));
}