diff options
author | Rich Hickey <richhickey@gmail.com> | 2008-04-20 17:41:15 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2008-04-20 17:41:15 +0000 |
commit | 37713c695d53f08de17b3daec013e7c396769ca9 (patch) | |
tree | b63901cd5b1b781da106ba53467211e3218e547f /src | |
parent | 9e24fabf1232f129e5aac45802cce6dfd5e300ce (diff) |
made lazy-cons lazy for both first and rest
Diffstat (limited to 'src')
-rw-r--r-- | src/boot.clj | 10 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LazySeq.java | 77 |
2 files changed, 82 insertions, 5 deletions
diff --git a/src/boot.clj b/src/boot.clj index bee1bc0f..9478262c 100644 --- a/src/boot.clj +++ b/src/boot.clj @@ -385,13 +385,13 @@ (defmacro lazy-cons "Expands to code which produces a seq object whose first is - first-expr (evaluated) and whose rest is rest-expr, which is not - evaluated until rest is called. rest-expr will be evaluated at most - once per step in the sequence, e.g. calling rest repeatedly on the - head of the seq evaluates rest-expr once - the value it yields is + first-expr and whose rest is rest-expr, neither of which is + evaluated until first/rest is called. Each expr will be evaluated at most + once per step in the sequence, e.g. calling first/rest repeatedly on the + same node of the seq evaluates first/rest-expr once - the values they yield are cached." [first-expr & rest-expr] - (list 'fnseq first-expr (list* `fn [] rest-expr))) + (list 'new 'clojure.lang.LazySeq (list `fn [] first-expr) (list* `fn [] rest-expr))) diff --git a/src/jvm/clojure/lang/LazySeq.java b/src/jvm/clojure/lang/LazySeq.java new file mode 100644 index 00000000..8ebcaf68 --- /dev/null +++ b/src/jvm/clojure/lang/LazySeq.java @@ -0,0 +1,77 @@ +/** + * Copyright (c) Rich Hickey. All rights reserved. + * The use and distribution terms for this software are covered by the + * Common Public License 1.0 (http://opensource.org/licenses/cpl.php) + * which can be found in the file CPL.TXT 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; + +public class LazySeq extends ASeq{ + +IFn _firstFn; +Object _first; +IFn _restFn; +ISeq _rest; + +public LazySeq(IFn firstFn, IFn restFn){ + this._firstFn = firstFn; + this._restFn = restFn; + this._first = null; + this._rest = null; +} + +LazySeq(IPersistentMap meta, Object first, ISeq rest){ + super(meta); + this._first = first; + this._rest = rest; +} + +synchronized public Object first(){ + if(_firstFn != null) + { + try + { + _first = _firstFn.invoke(); + } + catch(Exception ex) + { + throw new RuntimeException(ex); + } + _firstFn = null; + } + return _first; +} + +synchronized public ISeq rest(){ + //force sequential evaluation + first(); + if(_restFn != null) + { + try + { + _rest = (ISeq) _restFn.invoke(); + } + catch(Exception ex) + { + throw new RuntimeException(ex); + } + _restFn = null; + } + return _rest; +} + +synchronized public LazySeq withMeta(IPersistentMap meta){ + if(meta == meta()) + return this; + //force before copying + rest(); + return new LazySeq(meta, _first, _rest); +} + +} |