]> gitweb.factorcode.org Git - factor.git/commitdiff
lazy-lists: complete remaining lazy list operations
authorchris.double <chris.double@double.co.nz>
Wed, 13 Sep 2006 07:49:18 +0000 (07:49 +0000)
committerchris.double <chris.double@double.co.nz>
Wed, 13 Sep 2006 07:49:18 +0000 (07:49 +0000)
contrib/lazy-lists/lists.factor
contrib/lazy-lists/lists.facts

index 0dd4c4c6014fd71242ea3d4805e06384375cf6b6..33513477435fcf00d8c14f32e9faad0daef2a454 100644 (file)
@@ -2,10 +2,25 @@
 ! See http://factorcode.org/license.txt for BSD license.
 !
 ! Updated by Matthew Willis, July 2006
+! Updated by Chris Double, September 2006
 
 USING: kernel sequences math vectors arrays namespaces generic ;
 IN: lazy-lists
 
+TUPLE: promise quot forced? value ;
+
+C: promise ( quot -- promise ) [ set-promise-quot ] keep ;
+
+: force ( promise -- value )
+    #! Force the given promise leaving the value of calling the
+    #! promises quotation on the stack. Re-forcing the promise
+    #! will return the same value and not recall the quotation.
+    dup promise-forced? [
+        dup promise-quot call over set-promise-value
+        t over set-promise-forced?
+    ] unless
+    promise-value ;
+
 TUPLE: cons car cdr ;
 GENERIC: car  ( cons -- car )
 GENERIC: cdr  ( cons -- cdr )
@@ -18,6 +33,9 @@ C: cons ( car cdr -- list )
 M: cons car ( cons -- car )
     cons-car ;    
 
+M: cons cdr ( cons -- cdr )
+    cons-cdr ;    
+
 : nil ( -- cons )
   T{ cons f f f } ;
 
@@ -30,23 +48,9 @@ M: cons nil? ( cons -- bool )
 : 1list ( obj -- cons )
     nil <cons> ;
 
-: 2list ( obj obj -- cons )
+: 2list ( a b -- cons )
     nil <cons> <cons> ;
 
-TUPLE: promise quot forced? value ;
-
-C: promise ( quot -- promise ) [ set-promise-quot ] keep ;
-
-: force ( promise -- value )
-    #! Force the given promise leaving the value of calling the
-    #! promises quotation on the stack. Re-forcing the promise
-    #! will return the same value and not recall the quotation.
-    dup promise-forced? [
-        dup promise-quot call over set-promise-value
-        t over set-promise-forced?
-    ] unless
-    promise-value ;
-
 ! Both 'car' and 'cdr' are promises  
 : lazy-cons ( car cdr -- promise ) 
     >r <promise> r> <promise> <cons> 
@@ -80,15 +84,20 @@ TUPLE: list ;
 : uncons ( cons -- car cdr )
     #! Return the car and cdr of the lazy list
     dup car swap cdr ;
-    
+
+: leach ( list quot -- )
+  swap dup nil? [ 
+    2drop 
+  ] [
+    uncons swap pick call swap leach
+  ] if ;
+
 : 2curry ( a b quot -- quot )
   curry curry ;
 
 TUPLE: lazy-map cons quot ;
 
-: lmap ( list quot -- list )
-    #! Return a lazy list containing the collected result of calling
-    #! quot on the original lazy list.
+: lmap ( list quot -- result )
     over nil? [ 2drop nil ] [ <lazy-map> ] if ;
 
 M: lazy-map car ( lazy-map -- car )
@@ -99,11 +108,12 @@ M: lazy-map cdr ( lazy-map -- cdr )
   [ lazy-map-cons cdr ] keep
   lazy-map-quot lmap ;
 
+M: lazy-map nil? ( lazy-map -- bool )
+  lazy-map-cons nil? ;
+
 TUPLE: lazy-take n cons ;
 
-: ltake ( n list -- list )
-    #! Return a lazy list containing the first n items from
-    #! the original lazy list.
+: ltake ( n list -- result )
     over zero? [ 2drop nil ] [ <lazy-take> ] if ;
      
 M: lazy-take car ( lazy-take -- car )
@@ -113,6 +123,9 @@ M: lazy-take cdr ( lazy-take -- cdr )
   [ lazy-take-n 1- ] keep
   lazy-take-cons cdr ltake ;
 
+M: lazy-take nil? ( lazy-take -- bool )
+  lazy-take-n zero? ;
+
 TUPLE: lazy-subset cons quot ;
 
 : lsubset ( list quot -- list )
@@ -152,90 +165,50 @@ M: lazy-subset nil? ( lazy-subset -- bool )
     ] if 
   ] if ;
 
-: t1 
-  [ 1 ] [ [ 2 ] [ [ 3 ] [ nil ] cons ] cons ] cons ;
-
-: t2
-  [ 2 ] [ [ 3 ] [ [ 4 ] [ nil ] cons ] cons ] cons ;
-
-: (list>backwards-vector) ( list -- vector )
-    dup nil? [ drop V{ } clone ]
-       [ uncons (list>backwards-vector) swap over push ] if ;
-       
 : list>vector ( list -- vector )
-    #! Convert a lazy list to a vector. This will cause
-    #! an infinite loop if the lazy list is an infinite list.
-    (list>backwards-vector) reverse ;
+  [ [ , ] leach ] V{ } make ;
 
 : list>array ( list -- array )
-    list>vector >array ;
+  [ [ , ] leach ] { } make ;
 
-DEFER: backwards-vector>list
-: (backwards-vector>list) ( vector -- list )
-    dup empty? [ drop nil ]
-       [ dup pop swap backwards-vector>list cons ] if ;
+TUPLE: lazy-append list1 list2 ;
 
-DEFER: force-promise
+: lappend ( list1 list2 -- result )
+  {
+    { [ over nil? over nil? and ] [ 2drop nil ] }
+    { [ over nil? ] [ nip ] }
+    { [ dup nil? ] [ drop ] }
+    { [ t ] [ <lazy-append> ] }
+  } cond ;
 
-: backwards-vector>list ( vector -- list )
-    [ , \ (backwards-vector>list) , ] force-promise ;
-    
-: array>list ( array -- list )
-    #! Convert a list to a lazy list.
-    reverse >vector backwards-vector>list ;
-
-DEFER: lappend*
-: (lappend*) ( lists -- list )
-       dup nil? [ 
-               uncons >r dup nil? [ drop r> (lappend*) ]
-               [ uncons r> cons lappend* cons ] if
-       ] unless ;
-
-: lappend* ( llists -- list )
-    #! Given a lazy list of lazy lists, concatenate them 
-    #! together in a lazy fashion. The actual appending is 
-    #! done lazily on iteration rather than immediately
-    #! so it works very fast no matter how large the lists.
-       [ , \ (lappend*) , ] force-promise ;
-
-: lappend ( list1 list2 -- llist )
-    #! Concatenate two lazy lists such that they appear to be one big
-    #! lazy list.
-    lunit cons lappend* ;
+M: lazy-append car ( lazy-append -- car )
+  lazy-append-list1 car ;
+
+M: lazy-append cdr ( lazy-append -- cdr )
+  [ lazy-append-list1 cdr  ] keep
+  lazy-append-list2 lappend ;
+
+M: lazy-append nil? ( lazy-append -- bool )
+  dup lazy-append-list1 nil? [
+    drop t 
+  ] [
+    lazy-append-list2 nil? 
+  ] if ;
+
+TUPLE: lazy-from-by n quot ;
 
-: leach ( list quot -- )
-    #! Call the quotation on each item in the lazy list. 
-    #! Warning: If the list is infinite then this will
-    #! never return. 
-       swap dup nil? [ 2drop ] [
-               uncons swap pick call swap leach
-       ] if ;
-
-DEFER: lapply  
-: (lapply) ( list quot -- list )
-       over nil? [ drop ] [ 
-               swap dup car >r uncons pick call swap lapply
-               r> swap cons 
-       ] if ;
-       
-: lapply ( list quot -- list )
-    #! Returns a lazy list which is
-       #! (cons (car list)
-       #!                 (lapply (quot (car list) (cdr list)) quot))
-       #! This allows for complicated list functions
-    [ swap , , \ (lapply) , ] force-promise ;
-
-DEFER: lfrom-by
-: (lfrom-by) ( n quot -- list )
-       2dup call swap lfrom-by cons ;
-       
 : lfrom-by ( n quot -- list )
-    #! Return a lazy list of values starting from n, with
-    #! each successive value being the result of applying quot to
-    #! n.
-    [ swap , , \ (lfrom-by) , ] force-promise ;
+  <lazy-from-by> ;
     
 : lfrom ( n -- list )
-       #! Return a lazy list of increasing numbers starting
-       #! from the initial value 'n'.
-       [ 1 + ] lfrom-by ;
\ No newline at end of file
+  [ 1 + ] lfrom-by ;
+
+M: lazy-from-by car ( lazy-from-by -- car )
+  lazy-from-by-n ;
+
+M: lazy-from-by cdr ( lazy-from-by -- cdr )
+  [ lazy-from-by-n ] keep
+  lazy-from-by-quot dup >r call r> lfrom-by ;
+
+M: lazy-from-by nil? ( lazy-from-by -- bool )
+  drop f ;
index 86126f4a2c78547d3bbccec9e87dc9dc5bd3f29b..efed0d5a5d5a6c40f89d2553b7d532a4c16171ef 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2006 Chris Double.
 ! See http://factorcode.org/license.txt for BSD license.
 
-USING: help lazy-lists ;
+USING: help lazy-lists sequences ;
 
 HELP: <promise> 
 { $values { "quot" "a quotation with stack effect ( -- X )" } { "promise" "a promise object" } }
@@ -14,46 +14,116 @@ HELP: force
 { $see-also <promise> } ;
 
 HELP: <cons> 
-{ $values { "car" "A promise for the head of the lazy list" } { "cdr" "A promise for the tail of the lazy list" } { "cons" "a cons object" } }
-{ $description "Constructs a lazy cons cell. The car and cdr are promises that, when forced, provide the non-lazy values." }
-{ $see-also car cdr nil } ;
+{ $values { "car" "the head of the lazy list" } { "cdr" "the tail of the lazy list" } { "cons" "a cons object" } }
+{ $description "Constructs a cons cell." }
+{ $see-also cons car cdr nil nil? } ;
 
 HELP: car
 { $values { "cons" "a cons object" } { "car" "the first item in the list" } }
-{ $description "Returns the first item in the list. This causes the item to be evaluated." } 
-{ $see-also <cons> car cdr } ;
+{ $description "Returns the first item in the list." } 
+{ $see-also cons cdr nil nil? } ;
 
 HELP: cdr
 { $values { "cons" "a cons object" } { "cdr" "a cons object" } }
 { $description "Returns the tail of the list." } 
-{ $see-also <cons> car cdr } ;
-
-HELP: cons
-{ $values { "car" "a quotation with stack effect ( -- X )" } { "cdr" "a quotation with stack effect ( -- cons )" } { "cons" "the resulting cons object" } }
-{ $description "Constructs a cons object for a lazy list from two quotations. The 'car' quotation should return the head of the list, and the 'cons' quotation the tail when called." } 
-{ $see-also <cons> car cdr } ;
+{ $see-also cons car nil nil? } ;
 
 HELP: nil 
-{ $values { "array" "An empty array" } }
-{ $description "Returns a representation of an empty lazy list" } 
-{ $see-also <cons> car cdr nil? } ;
+{ $values { "cons" "An empty cons" } }
+{ $description "Returns a representation of an empty list" } 
+{ $see-also cons car cdr nil? } ;
 
 HELP: nil? 
 { $values { "cons" "a cons object" } }
-{ $description "Return true if the cons object is the nil list." } 
-{ $see-also nil } ;
+{ $description "Return true if the cons object is the nil cons." } 
+{ $see-also cons car cdr nil  } ;
 
-HELP: <list>
-{ $values { "car" "the car of the list" } { "cdr" "a <cons> object for the cdr of the list" } { "list" "a lazy list" } }
-{ $description "Constructs a lazy list where the car is already forced and the cdr is an already forced list." } 
-{ $see-also car cdr } ;
+HELP: cons 
+{ $values { "car" "the head of the lazy list" } { "cdr" "the tail of the lazy list" } { "cons" "a cons object" } }
+{ $description "Constructs a cons cell." }
+{ $see-also car cdr nil nil? } ;
 
 HELP: 1list
-{ $values { "obj" "an object" } { "list" "a list" } }
+{ $values { "obj" "an object" } { "cons" "a cons object" } }
 { $description "Create a list with 1 element." } 
-{ $see-also <list> 2list } ;
+{ $see-also 2list } ;
 
 HELP: 2list
-{ $values { "a" "an object" } { "b" "an object" } { "list" "a list" } }
+{ $values { "a" "an object" } { "b" "an object" } { "cons" "a cons object" } }
 { $description "Create a list with 2 elements." } 
-{ $see-also <list> 1list } ;
+{ $see-also 1list } ;
+
+HELP: lazy-cons
+{ $values { "car" "a quotation with stack effect ( -- X )" } { "cdr" "a quotation with stack effect ( -- cons )" } { "cons" "the resulting cons object" } }
+{ $description "Constructs a cons object for a lazy list from two quotations. The 'car' quotation should return the head of the list, and the 'cons' quotation the tail when called. When " { $link cons } " or " { $link cdr } " are called on the lazy-cons object then the appropriate quotation is called." } 
+{ $see-also cons car cdr nil nil? } ;
+
+HELP: 1lazy-list
+{ $values { "a" "a quotation with stack effect ( -- X )" } { "lazy-cons" "a lazy-cons object" } }
+{ $description "Create a lazy list with 1 element. The element is the result of calling the quotation. The quotation is only called when the list element is requested." } 
+{ $see-also 2lazy-list 3lazy-list } ;
+
+HELP: 2lazy-list
+{ $values { "a" "a quotation with stack effect ( -- X )" } { "b" "a quotation with stack effect ( -- X )" } { "lazy-cons" "a lazy-cons object" } }
+{ $description "Create a lazy list with 2 elements. The elements are the result of calling the quotations. The quotations are only called when the list elements are requested." } 
+{ $see-also 1lazy-list 3lazy-list } ;
+
+HELP: 3lazy-list
+{ $values { "a" "a quotation with stack effect ( -- X )" } { "b" "a quotation with stack effect ( -- X )" } { "c" "a quotation with stack effect ( -- X )" } { "lazy-cons" "a lazy-cons object" } }
+{ $description "Create a lazy list with 3 elements. The elements are the result of calling the quotations. The quotations are only called when the list elements are requested." } 
+{ $see-also 1lazy-list 2lazy-list } ;
+
+HELP: lnth
+{ $values { "n" "an integer index" } { "list" "a cons object" } { "elt" "the element at the nth index" } }
+{ $description "Outputs the nth element of the list." } 
+{ $see-also cons car cdr } ;
+
+HELP: uncons
+{ $values { "cons" "a cons object" } { "car" "the head of the list" } { "cdr" "the tail of the list" } }
+{ $description "Put the head and tail of the list on the stack." } 
+{ $see-also cons car cdr } ;
+
+HELP: leach
+{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( -- )" } }
+{ $description "Call the quotation for each item in the list." } 
+{ $see-also lmap ltake lsubset lappend lfrom lfrom-by } ;
+
+HELP: lmap
+{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( -- X )" } { "result" "resulting cons object" } }
+{ $description "Perform a similar functionality to that of the " { $link map } " word, but in a lazy manner. No evaluation of the list elements occurs initially but a " { $link <lazy-map> } " object is returned which conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required." } 
+{ $see-also leach ltake lsubset lappend lfrom lfrom-by } ;
+
+HELP: ltake
+{ $values { "n" "a non negative integer" } { "list" "a cons object" } { "result" "resulting cons object" } }
+{ $description "Outputs a lazy list containing the first n items in the list. This is done a lazy manner. No evaluation of the list elements occurs initially but a " { $link <lazy-take> } " object is returned which conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required." } 
+{ $see-also leach lmap lsubset lappend lfrom lfrom-by } ;
+
+HELP: lsubset
+{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( -- X )" } { "result" "resulting cons object" } }
+{ $description "Perform a similar functionality to that of the " { $link subset } " word, but in a lazy manner. No evaluation of the list elements occurs initially but a " { $link <lazy-subset> } " object is returned which conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required." } 
+{ $see-also leach lmap ltake lappend lfrom lfrom-by } ;
+
+HELP: list>vector
+{ $values { "list" "a cons object" } { "vector" "the list converted to a vector" } }
+{ $description "Convert a list to a vector. If the list is a lazy infinite list then this will enter an infinite loop." } 
+{ $see-also list>array } ;
+
+HELP: list>array
+{ $values { "list" "a cons object" } { "array" "the list converted to an array" } }
+{ $description "Convert a list to an array. If the list is a lazy infinite list then this will enter an infinite loop." } 
+{ $see-also list>vector } ;
+
+HELP: lappend
+{ $values { "list1" "a cons object" } { "list2" "a cons object" } { "result" "a lazy list of list2 appended to list1" } }
+{ $description "Perform a similar functionality to that of the " { $link append } " word, but in a lazy manner. No evaluation of the list elements occurs initially but a " { $link <lazy-append> } " object is returned which conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required. Successive calls to " { $link cdr } " will iterate through list1, followed by list2." } 
+{ $see-also leach lmap ltake lsubset lfrom lfrom-by } ;
+
+HELP: lfrom-by
+{ $values { "n" "an integer" } { "quot" "a quotation with stack effect ( -- int )" } { "result" "a lazy list of integers" } }
+{ $description "Return an infinite lazy list of values starting from n, with each successive value being the result of applying quot to n." } 
+{ $see-also leach lmap ltake lsubset lfrom } ;
+
+HELP: lfrom
+{ $values { "n" "an integer" } { "result" "a lazy list of integers" } }
+{ $description "Return an infinite lazy list of incrementing integers starting from n." } 
+{ $see-also leach lmap ltake lsubset lfrom-by } ;