diff options
author | Rich Hickey <richhickey@gmail.com> | 2009-01-30 00:03:15 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2009-01-30 00:03:15 +0000 |
commit | 42715f9d8ab764a89e3f69cd2c508901a24fc881 (patch) | |
tree | 83eae41ed955a41d96b078c5e571148f658a8573 /src | |
parent | e8a3530e6f07275cb1a176a6bba2eca42d258e40 (diff) |
[lazy] added more to ISeq
Diffstat (limited to 'src')
23 files changed, 71 insertions, 251 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index ca3acfac..2cf79beb 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -391,30 +391,6 @@ [item & more] (spread (cons item more))) -(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 - will cache the result and return it on all subsequent force calls" - [& body] - (list 'new 'clojure.lang.Delay (list* `fn [] body))) - -(defn delay? - "returns true if x is a Delay created with delay" - [x] (instance? clojure.lang.Delay x)) - -(defn force - "If x is a Delay, returns the (possibly cached) value of its expression, else returns x" - [x] (. clojure.lang.Delay (force x))) - -(defn fnseq - "Returns a seq object whose first is first and whose rest is the - value produced by calling restfn with no arguments. restfn will be - called at most once per step in the sequence, e.g. calling rest - repeatedly on the head of the seq calls restfn once - the value it - yields is cached." - [first restfn] - (new clojure.lang.FnSeq first restfn)) - (defmacro lazy-cons "Expands to code which produces a seq object whose first is first-expr and whose rest is rest-expr, neither of which is @@ -425,21 +401,6 @@ [first-expr & rest-expr] (list 'new 'clojure.lang.LazyCons (list `fn (list [] first-expr) (list* [(gensym)] rest-expr)))) -;(defmacro lazy-seq -; "Expands to code which produces a seq object whose first is the -; value of first-expr and whose rest is the value of rest-expr, -; neither of which is evaluated until first/rest is called. Each expr -; will be evaluated every step in the sequence, e.g. calling -; first/rest repeatedly on the same node of the seq evaluates -; first/rest-expr repeatedly - the values they yield are not cached." -; [first-expr rest-expr] -; (list 'new 'clojure.lang.LazySeq (list `fn (list [] first-expr) (list [(gensym)] rest-expr)))) - -(defn cache-seq - "Given a seq s, returns a lazy seq that will touch each element of s - at most once, caching the results." - [s] (when s (clojure.lang.CachedSeq. s))) - (defn concat "Returns a lazy seq representing the concatenation of the elements in the supplied colls." ([] nil) @@ -457,6 +418,23 @@ (cat (concat x y) zs)))) ;;;;;;;;;;;;;;;;at this point all the support for syntax-quote exists;;;;;;;;;;;;;;;;;;;;;; +(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 + will cache the result and return it on all subsequent force + calls. Any closed over locals will be cleared prior to the tail call + of body, (i.e. they will not be retained)." + [& body] + (list 'new 'clojure.lang.Delay (list* `#^{:once true} fn* [] body))) + +(defn delay? + "returns true if x is a Delay created with delay" + [x] (instance? clojure.lang.Delay x)) + +(defn force + "If x is a Delay, returns the (possibly cached) value of its expression, else returns x" + [x] (. clojure.lang.Delay (force x))) + (defmacro if-not "Evaluates test. If logical false, evaluates and returns then expr, otherwise else expr, if supplied, else nil." ([test then] `(if-not ~test ~then nil)) diff --git a/src/jvm/clojure/lang/APersistentMap.java b/src/jvm/clojure/lang/APersistentMap.java index 4d8bc8f7..fd700e0e 100644 --- a/src/jvm/clojure/lang/APersistentMap.java +++ b/src/jvm/clojure/lang/APersistentMap.java @@ -130,7 +130,7 @@ static public class KeySeq extends ASeq{ return ((Map.Entry) seq.first()).getKey();
}
- public ISeq rest(){
+ public Seqable more(){
return create(seq.rest());
}
@@ -161,7 +161,7 @@ static public class ValSeq extends ASeq{ return ((Map.Entry) seq.first()).getValue();
}
- public ISeq rest(){
+ public Seqable more(){
return create(seq.rest());
}
diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java index 4cb753a8..8e6a85b8 100644 --- a/src/jvm/clojure/lang/APersistentVector.java +++ b/src/jvm/clojure/lang/APersistentVector.java @@ -438,7 +438,7 @@ public IStream stream() throws Exception { return v.nth(i); } - public ISeq rest(){ + public Seqable more(){ if(i + 1 < v.count()) return new APersistentVector.Seq(v, i + 1); return null; @@ -490,7 +490,7 @@ static class RSeq extends ASeq implements IndexedSeq{ return v.nth(i); } - public ISeq rest(){ + public Seqable more(){ if(i > 0) return new APersistentVector.RSeq(v, i - 1); return null; diff --git a/src/jvm/clojure/lang/ASeq.java b/src/jvm/clojure/lang/ASeq.java index 8bd830d1..c4f4f7ca 100644 --- a/src/jvm/clojure/lang/ASeq.java +++ b/src/jvm/clojure/lang/ASeq.java @@ -110,6 +110,10 @@ public ISeq cons(Object o){ return new Cons(o, this);
}
+public ISeq rest(){
+ return RT.seq(more());
+}
+
// java.util.Collection implementation
public Object[] toArray(){
diff --git a/src/jvm/clojure/lang/ArraySeq.java b/src/jvm/clojure/lang/ArraySeq.java index bbe3b199..f0d825a4 100644 --- a/src/jvm/clojure/lang/ArraySeq.java +++ b/src/jvm/clojure/lang/ArraySeq.java @@ -65,7 +65,7 @@ public Object first(){ return Reflector.prepRet(Array.get(array, i)); } -public ISeq rest(){ +public Seqable more(){ if(oa != null) { if(i + 1 < oa.length) @@ -138,7 +138,7 @@ static public class ArraySeq_int extends ASeq implements IndexedSeq, IReduce{ return array[i]; } - public ISeq rest(){ + public Seqable more(){ if(i + 1 < array.length) return new ArraySeq_int(meta(), array, i + 1); return null; @@ -186,7 +186,7 @@ static public class ArraySeq_float extends ASeq implements IndexedSeq, IReduce{ return array[i]; } - public ISeq rest(){ + public Seqable more(){ if(i + 1 < array.length) return new ArraySeq_float(meta(), array, i + 1); return null; @@ -233,7 +233,7 @@ static public class ArraySeq_double extends ASeq implements IndexedSeq, IReduce{ return array[i]; } - public ISeq rest(){ + public Seqable more(){ if(i + 1 < array.length) return new ArraySeq_double(meta(), array, i + 1); return null; @@ -280,7 +280,7 @@ static public class ArraySeq_long extends ASeq implements IndexedSeq, IReduce{ return array[i]; } - public ISeq rest(){ + public Seqable more(){ if(i + 1 < array.length) return new ArraySeq_long(meta(), array, i + 1); return null; diff --git a/src/jvm/clojure/lang/CachedSeq.java b/src/jvm/clojure/lang/CachedSeq.java deleted file mode 100644 index 7d21952d..00000000 --- a/src/jvm/clojure/lang/CachedSeq.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) Rich Hickey. All rights reserved. - * The use and distribution terms for this software are covered by the - * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) - * which can be found in the file epl-v10.html at the root of this distribution. - * By using this software in any fashion, you are agreeing to be bound by - * the terms of this license. - * You must not remove this notice, or any other, from this software. - **/ - -/* rich Aug 10, 2008 */ - -package clojure.lang; - -public class CachedSeq extends ASeq{ -ISeq s; -Object _first; -ISeq _rest; - -public CachedSeq(ISeq s){ - this.s = s; - this._first = this; - this._rest = this; -} - -CachedSeq(IPersistentMap meta, Object first, ISeq rest){ - super(meta); - this._first = first; - this._rest = rest; -} - -final -synchronized -public Object first(){ - if(_first == this) - _first = s.first(); - return _first; -} - -final -synchronized -public ISeq rest(){ - if(_rest == this) - { - //force sequential evaluation - if(_first == this) - first(); - ISeq rs = s.rest(); - if(rs == null) - _rest = rs; - else - _rest = new CachedSeq(rs); - s = null; - } - return _rest; -} - -public CachedSeq withMeta(IPersistentMap meta){ - if(meta == meta()) - return this; - //force before copying - rest(); - return new CachedSeq(meta, _first, _rest); -} -} diff --git a/src/jvm/clojure/lang/Cons.java b/src/jvm/clojure/lang/Cons.java index c9e65eb3..a120aa19 100644 --- a/src/jvm/clojure/lang/Cons.java +++ b/src/jvm/clojure/lang/Cons.java @@ -15,30 +15,30 @@ package clojure.lang; public class Cons extends ASeq{ private final Object _first; -private final ISeq _rest; +private final Seqable _more; -public Cons(Object first, ISeq rest){ +public Cons(Object first, Seqable _more){ this._first = first; - this._rest = rest; + this._more = _more; } -public Cons(IPersistentMap meta, Object _first, ISeq _rest){ +public Cons(IPersistentMap meta, Object _first, Seqable _more){ super(meta); this._first = _first; - this._rest = _rest; + this._more = _more; } public Object first(){ return _first; } -public ISeq rest(){ - return _rest; +public Seqable more(){ + return _more; } public int count(){ - return 1 + RT.count(_rest); + return 1 + RT.count(_more); } public ISeq seq(){ @@ -46,6 +46,6 @@ public ISeq seq(){ } public Cons withMeta(IPersistentMap meta){ - return new Cons(meta, _first, _rest); + return new Cons(meta, _first, _more); } } diff --git a/src/jvm/clojure/lang/Delay.java b/src/jvm/clojure/lang/Delay.java index a0dfd0b6..eed98fd0 100644 --- a/src/jvm/clojure/lang/Delay.java +++ b/src/jvm/clojure/lang/Delay.java @@ -35,4 +35,21 @@ synchronized Object get() throws Exception{ } return val; } + + static public class Seq extends Delay implements Seqable{ + public Seq(IFn fn) { + super(fn); + } + + public ISeq seq() { + try + { + return (ISeq) get(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + } } diff --git a/src/jvm/clojure/lang/EnumerationSeq.java b/src/jvm/clojure/lang/EnumerationSeq.java index 7c579651..2cd7688c 100644 --- a/src/jvm/clojure/lang/EnumerationSeq.java +++ b/src/jvm/clojure/lang/EnumerationSeq.java @@ -52,7 +52,7 @@ public Object first(){ return state.val; } -public ISeq rest(){ +public Seqable more(){ if(state._rest == state) synchronized(state) { diff --git a/src/jvm/clojure/lang/FnSeq.java b/src/jvm/clojure/lang/FnSeq.java deleted file mode 100644 index f8d2098f..00000000 --- a/src/jvm/clojure/lang/FnSeq.java +++ /dev/null @@ -1,62 +0,0 @@ -/**
- * Copyright (c) Rich Hickey. All rights reserved.
- * The use and distribution terms for this software are covered by the
- * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
- * which can be found in the file epl-v10.html at the root of this distribution.
- * By using this software in any fashion, you are agreeing to be bound by
- * the terms of this license.
- * You must not remove this notice, or any other, from this software.
- **/
-
-package clojure.lang;
-
-public class FnSeq extends ASeq{
-
-final Object _first;
-IFn _restFn;
-//volatile
-ISeq _rest;
-
-public FnSeq(Object first, IFn restFn){
- this._first = first;
- this._restFn = restFn;
- this._rest = this;
-}
-
-public FnSeq(IPersistentMap meta, Object first, IFn restFn, ISeq rest){
- super(meta);
- this._first = first;
- this._rest = rest;
- this._restFn = restFn;
-}
-
-public Object first(){
- return _first;
-}
-
-synchronized public ISeq rest(){
- if(_restFn != null)
- {
- try
- {
- _rest = (ISeq) _restFn.invoke();
- }
- catch(Exception ex)
- {
- throw new Error(ex);
- }
- _restFn = null;
- }
- return _rest;
-}
-
-
-synchronized public FnSeq withMeta(IPersistentMap meta){
- if(meta == meta())
- return this;
- //force eval of restFn before copying
- rest();
- return new FnSeq(meta, _first, _restFn, _rest);
-}
-
-}
diff --git a/src/jvm/clojure/lang/ISeq.java b/src/jvm/clojure/lang/ISeq.java index 2e7adb3b..4a24b2b1 100644 --- a/src/jvm/clojure/lang/ISeq.java +++ b/src/jvm/clojure/lang/ISeq.java @@ -22,6 +22,8 @@ Object first(); ISeq rest();
+Seqable more();
+
ISeq cons(Object o);
}
diff --git a/src/jvm/clojure/lang/IteratorSeq.java b/src/jvm/clojure/lang/IteratorSeq.java index 4a5ab80c..6015428c 100644 --- a/src/jvm/clojure/lang/IteratorSeq.java +++ b/src/jvm/clojure/lang/IteratorSeq.java @@ -50,7 +50,7 @@ public Object first(){ return state.val;
}
-public ISeq rest(){
+public Seqable more(){
if(state._rest == state)
synchronized(state)
{
diff --git a/src/jvm/clojure/lang/LazyCons.java b/src/jvm/clojure/lang/LazyCons.java index ee60a891..20daba01 100644 --- a/src/jvm/clojure/lang/LazyCons.java +++ b/src/jvm/clojure/lang/LazyCons.java @@ -49,7 +49,7 @@ public Object first(){ final synchronized -public ISeq rest(){ +public Seqable more(){ if(_rest == sentinel) { try diff --git a/src/jvm/clojure/lang/LazySeq.java b/src/jvm/clojure/lang/LazySeq.java deleted file mode 100644 index ea66333f..00000000 --- a/src/jvm/clojure/lang/LazySeq.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) Rich Hickey. All rights reserved. - * The use and distribution terms for this software are covered by the - * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) - * which can be found in the file epl-v10.html at the root of this distribution. - * By using this software in any fashion, you are agreeing to be bound by - * the terms of this license. - * You must not remove this notice, or any other, from this software. - **/ - -/* rich Apr 20, 2008 */ - -package clojure.lang; - -final public class LazySeq extends ASeq{ -final IFn f; - -public LazySeq(IFn f){ - this.f = f; -} - -final public Object first(){ - try - { - return f.invoke(); - } - catch(Exception e) - { - throw new RuntimeException(e); - } -} - -final public ISeq rest(){ - try - { - return RT.seq(f.invoke(null)); - } - catch(Exception e) - { - throw new RuntimeException(e); - } -} - -LazySeq(IPersistentMap meta, IFn f){ - super(meta); - this.f = f; -} - -public Obj withMeta(IPersistentMap meta){ - if(meta == meta()) - return this; - return new LazySeq(meta, f); -} -} diff --git a/src/jvm/clojure/lang/PersistentArrayMap.java b/src/jvm/clojure/lang/PersistentArrayMap.java index d8fbd354..6fa05319 100644 --- a/src/jvm/clojure/lang/PersistentArrayMap.java +++ b/src/jvm/clojure/lang/PersistentArrayMap.java @@ -216,7 +216,7 @@ static class Seq extends ASeq{ return new MapEntry(array[i],array[i+1]);
}
- public ISeq rest(){
+ public Seqable more(){
if(i + 2 < array.length)
return new Seq(array, i + 2);
return null;
diff --git a/src/jvm/clojure/lang/PersistentHashMap.java b/src/jvm/clojure/lang/PersistentHashMap.java index d696cd5a..f4c700e4 100644 --- a/src/jvm/clojure/lang/PersistentHashMap.java +++ b/src/jvm/clojure/lang/PersistentHashMap.java @@ -349,7 +349,7 @@ final static class FullNode implements INode{ return s.first(); } - public ISeq rest(){ + public Seqable more(){ ISeq nexts = s.rest(); if(nexts != null) return new Seq(nexts, i, node); @@ -507,7 +507,7 @@ final static class BitmapIndexedNode implements INode{ return s.first(); } - public ISeq rest(){ + public Seqable more(){ ISeq nexts = s.rest(); if(nexts != null) return new Seq(nexts, i, node); diff --git a/src/jvm/clojure/lang/PersistentList.java b/src/jvm/clojure/lang/PersistentList.java index b3949007..7fa3e859 100644 --- a/src/jvm/clojure/lang/PersistentList.java +++ b/src/jvm/clojure/lang/PersistentList.java @@ -64,7 +64,7 @@ public Object first(){ return _first;
}
-public ISeq rest(){
+public Seqable more(){
if(_count == 1)
return null;
return (ISeq) _rest;
diff --git a/src/jvm/clojure/lang/PersistentQueue.java b/src/jvm/clojure/lang/PersistentQueue.java index 552cdb42..f2205741 100644 --- a/src/jvm/clojure/lang/PersistentQueue.java +++ b/src/jvm/clojure/lang/PersistentQueue.java @@ -140,7 +140,7 @@ static class Seq extends ASeq{ return f.first();
}
- public ISeq rest(){
+ public Seqable more(){
ISeq f1 = f.rest();
ISeq r1 = rseq;
if(f1 == null)
diff --git a/src/jvm/clojure/lang/PersistentStructMap.java b/src/jvm/clojure/lang/PersistentStructMap.java index 01e86346..affad2fe 100644 --- a/src/jvm/clojure/lang/PersistentStructMap.java +++ b/src/jvm/clojure/lang/PersistentStructMap.java @@ -216,7 +216,7 @@ static class Seq extends ASeq{ return new MapEntry(keys.first(), vals[i]); } - public ISeq rest(){ + public Seqable more(){ if(i + 1 < vals.length) return new Seq(_meta, keys.rest(), vals, i + 1, ext); return ext.seq(); diff --git a/src/jvm/clojure/lang/PersistentTreeMap.java b/src/jvm/clojure/lang/PersistentTreeMap.java index 1cd40969..035c01eb 100644 --- a/src/jvm/clojure/lang/PersistentTreeMap.java +++ b/src/jvm/clojure/lang/PersistentTreeMap.java @@ -781,7 +781,7 @@ static public class Seq extends ASeq{ return stack.first(); } - public ISeq rest(){ + public Seqable more(){ Node t = (Node) stack.first(); ISeq nextstack = push(asc ? t.right() : t.left(), stack.rest(), asc); if(nextstack != null) diff --git a/src/jvm/clojure/lang/Range.java b/src/jvm/clojure/lang/Range.java index 226a77ba..59d3dda3 100644 --- a/src/jvm/clojure/lang/Range.java +++ b/src/jvm/clojure/lang/Range.java @@ -39,7 +39,7 @@ public Object first(){ return n; } -public ISeq rest(){ +public Seqable more(){ if(n < end-1) return new Range(_meta, n + 1, end); return null; diff --git a/src/jvm/clojure/lang/StreamSeq.java b/src/jvm/clojure/lang/StreamSeq.java index 44cfe28c..dfc8cf63 100644 --- a/src/jvm/clojure/lang/StreamSeq.java +++ b/src/jvm/clojure/lang/StreamSeq.java @@ -41,7 +41,7 @@ public class StreamSeq extends ASeq { return _first; } - synchronized public ISeq rest() { + synchronized public Seqable more() { if (stream != null) { try { _rest = create(stream); diff --git a/src/jvm/clojure/lang/StringSeq.java b/src/jvm/clojure/lang/StringSeq.java index cf370224..f5800f45 100644 --- a/src/jvm/clojure/lang/StringSeq.java +++ b/src/jvm/clojure/lang/StringSeq.java @@ -38,7 +38,7 @@ public Object first(){ return Character.valueOf(s.charAt(i)); } -public ISeq rest(){ +public Seqable more(){ if(i + 1 < s.length()) return new StringSeq(_meta, s, i + 1); return null; |