cons>> car ;
M: lazy-until cdr ( lazy-until -- cdr )
- [ cons>> uncons ] keep quot>> tuck call( elt -- ? )
+ [ cons>> unswons ] keep quot>> tuck call( elt -- ? )
[ 2drop nil ] [ luntil ] if ;
M: lazy-until nil? ( lazy-until -- bool )
dup nil? [
drop nil
] [
- uncons swap (lconcat)
+ uncons (lconcat)
] if ;
M: lazy-concat car ( lazy-concat -- car )
! Copyright (C) 2006 Chris Double.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel help.markup help.syntax ;
-
+USING: kernel help.markup help.syntax arrays sequences math quotations ;
IN: lists
-{ car cons cdr nil nil? list? uncons } related-words
+ABOUT: "lists"
+
+ARTICLE: "lists" "Lists"
+"The " { $vocab-link "lists" } " vocabulary implements linked lists. There are simple strict linked lists, but a generic list protocol allows the implementation of lazy lists as well."
+{ $subsection { "lists" "protocol" } }
+{ $subsection { "lists" "strict" } }
+{ $subsection { "lists" "manipulation" } }
+{ $subsection { "lists" "combinators" } }
+{ $vocab-subsection "Lazy lists" "lists.lazy" } ;
+
+ARTICLE: { "lists" "protocol" } "The list protocol"
+"Lists are instances of a mixin class"
+{ $subsection list }
+"Instances of the mixin must implement the following words:"
+{ $subsection car }
+{ $subsection cdr }
+{ $subsection nil? } ;
+
+ARTICLE: { "lists" "strict" } "Strict lists"
+"Strict lists are simply cons cells where the car and cdr have already been evaluated. These are the lists of Lisp. To construct a strict list, the following words are provided:"
+{ $subsection cons }
+{ $subsection swons }
+{ $subsection sequence>cons }
+{ $subsection deep-sequence>cons }
+{ $subsection 1list }
+{ $subsection 2list }
+{ $subsection 3list } ;
+
+ARTICLE: { "lists" "combinators" } "Combinators for lists"
+"Several combinators exist for list traversal."
+{ $subsection leach }
+{ $subsection lmap }
+{ $subsection foldl }
+{ $subsection foldr }
+{ $subsection lmap>array }
+{ $subsection lmap-as }
+{ $subsection traverse } ;
+
+ARTICLE: { "lists" "manipulation" } "Manipulating lists"
+"To get at the contents of a list:"
+{ $subsection uncons }
+{ $subsection unswons }
+{ $subsection lnth }
+{ $subsection cadr }
+{ $subsection llength }
+"To get a new list from an old one:"
+{ $subsection lreverse }
+{ $subsection lappend }
+{ $subsection lcut } ;
HELP: cons
-{ $values { "car" "the head of the lazy list" } { "cdr" "the tail of the lazy list" } { "cons" "a cons object" } }
+{ $values { "car" "the head of the list cell" } { "cdr" "the tail of the list cell" } { "cons" "a cons object" } }
+{ $description "Constructs a cons cell." } ;
+
+HELP: swons
+{ $values { "cdr" "the tail of the list cell" } { "car" "the head of the list cell" } { "cons" "a cons object" } }
{ $description "Constructs a cons cell." } ;
+{ cons swons uncons unswons } related-words
+
HELP: car
{ $values { "cons" "a cons object" } { "car" "the first item in the list" } }
{ $description "Returns the first item in the list." } ;
HELP: cdr
{ $values { "cons" "a cons object" } { "cdr" "a cons object" } }
{ $description "Returns the tail of the list." } ;
-
+
+{ car cdr } related-words
+
HELP: nil
{ $values { "symbol" "The empty cons (+nil+)" } }
{ $description "Returns a symbol representing the empty list" } ;
{ $values { "object" object } { "?" "a boolean" } }
{ $description "Return true if the cons object is the nil cons." } ;
+{ nil nil? } related-words
+
HELP: list? ( object -- ? )
{ $values { "object" "an object" } { "?" "a boolean" } }
{ $description "Returns true if the object conforms to the list protocol." } ;
HELP: 3list
{ $values { "a" "an object" } { "b" "an object" } { "c" "an object" } { "cons" "a cons object" } }
{ $description "Create a list with 3 elements." } ;
-
+
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 lnth cons car cdr } ;
HELP: uncons
-{ $values { "cons" "a cons object" } { "cdr" "the tail of the list" } { "car" "the head of the list" } }
+{ $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." } ;
+
+HELP: unswons
+{ $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." } ;
{ leach foldl lmap>array } related-words
HELP: lmap
{ $values { "list" "a cons object" } { "quot" { $quotation "( old -- new )" } } { "result" "the final result" } }
{ $description "Applies the quotation to each element of the list in order, collecting the new elements into a new list." } ;
-
+
HELP: lreverse
-{ $values { "list" "a cons object" } { "newlist" "a new cons object" } }
-{ $description "Reverses the input list, outputing a new, reversed list" } ;
-
-HELP: list>seq
-{ $values { "list" "a cons object" } { "array" "an array object" } }
+{ $values { "list" list } { "newlist" list } }
+{ $description "Reverses the input list, outputing a new, reversed list. The output is a strict cons list." } ;
+
+HELP: list>array
+{ $values { "list" "a cons object" } { "array" array } }
{ $description "Turns the given cons object into an array, maintaing order." } ;
-
-HELP: seq>list
-{ $values { "seq" "a sequence" } { "list" "a cons object" } }
+
+HELP: sequence>cons
+{ $values { "sequence" sequence } { "list" cons } }
{ $description "Turns the given array into a cons object, maintaing order." } ;
-
-HELP: cons>seq
-{ $values { "cons" "a cons object" } { "array" "an array object" } }
+
+HELP: deep-list>array
+{ $values { "list" list } { "array" array } }
{ $description "Recursively turns the given cons object into an array, maintaing order and also converting nested lists." } ;
-
-HELP: seq>cons
-{ $values { "seq" "a sequence object" } { "cons" "a cons object" } }
+
+HELP: deep-sequence>cons
+{ $values { "sequence" sequence } { "cons" cons } }
{ $description "Recursively turns the given sequence into a cons object, maintaing order and also converting nested lists." } ;
-
+
HELP: traverse
{ $values { "list" "a cons object" } { "pred" { $quotation "( list/elt -- ? )" } }
{ "quot" { $quotation "( list/elt -- result)" } } { "result" "a new cons object" } }
{ $description "Recursively traverses the list object, replacing any elements (which can themselves be sublists) that pred"
- " returns true for with the result of applying quot to." } ;
-
+ " returns true for with the result of applying quot to." } ;
+
+HELP: list
+{ $class-description "The class of lists. All lists are expected to conform to " { $link { "lists" "protocol" } } "." } ;
+
+HELP: cadr
+{ $values { "list" list } { "elt" object } }
+{ $description "Returns the second element of the list, ie the car of the cdr." } ;
+
+HELP: lappend
+{ $values { "list1" list } { "list2" list } { "newlist" list } }
+{ $description "Appends the two lists to form a new list. The first list must be finite. The result is a strict cons cell, and the first list is exausted." } ;
+
+HELP: lcut
+{ $values { "list" list } { "index" integer } { "before" cons } { "after" cons } }
+{ $description "Analogous to " { $link cut } ", this word cuts a list into two pieces at the given index." } ;
+
+HELP: lmap>array
+{ $values { "list" list } { "quot" quotation } { "array" array } }
+{ $description "Executes the quotation on each element of the list, collecting the results in an array." } ;
+
+HELP: lmap-as
+{ $values { "list" list } { "quot" quotation } { "exemplar" sequence } { "sequence" sequence } }
+{ $description "Executes the quotation on each element of the list, collecting the results in a sequence of the type given by the exemplar." } ;
IN: lists.tests
{ { 3 4 5 6 7 } } [
- { 1 2 3 4 5 } seq>list [ 2 + ] lmap list>seq
+ { 1 2 3 4 5 } sequence>cons [ 2 + ] lmap list>array
] unit-test
{ { 3 4 5 6 } } [
+nil+ } } }
+nil+ } } }
} [
- { 1 2 { 3 4 { 5 } } } seq>cons
+ { 1 2 { 3 4 { 5 } } } deep-sequence>cons
] unit-test
{ { 1 2 { 3 4 { 5 } } } } [
- { 1 2 { 3 4 { 5 } } } seq>cons cons>seq
+ { 1 2 { 3 4 { 5 } } } deep-sequence>cons deep-list>array
] unit-test
{ T{ cons f 2 T{ cons f 3 T{ cons f 4 T{ cons f 5 +nil+ } } } } } [
- { 1 2 3 4 } seq>cons [ 1+ ] lmap
+ { 1 2 3 4 } sequence>cons [ 1+ ] lmap
] unit-test
{ 15 } [
- { 1 2 3 4 5 } seq>list 0 [ + ] foldr
+ { 1 2 3 4 5 } sequence>cons 0 [ + ] foldr
] unit-test
{ { 5 4 3 2 1 } } [
- { 1 2 3 4 5 } seq>list lreverse list>seq
+ { 1 2 3 4 5 } sequence>cons lreverse list>array
] unit-test
{ 5 } [
- { 1 2 3 4 5 } seq>list llength
+ { 1 2 3 4 5 } sequence>cons llength
] unit-test
{ { 3 4 { 5 6 { 7 } } } } [
- { 1 2 { 3 4 { 5 } } } seq>cons [ atom? ] [ 2 + ] traverse cons>seq
+ { 1 2 { 3 4 { 5 } } } deep-sequence>cons [ atom? ] [ 2 + ] traverse deep-list>array
] unit-test
{ { 1 2 3 4 5 6 } } [
- { 1 2 3 } seq>list { 4 5 6 } seq>list lappend list>seq
-] unit-test
\ No newline at end of file
+ { 1 2 3 } sequence>cons { 4 5 6 } sequence>cons lappend list>array
+] unit-test
! Copyright (C) 2008 James Cash
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel sequences accessors math arrays vectors classes words locals ;
+USING: kernel sequences accessors math arrays vectors classes words
+combinators.short-circuit combinators ;
IN: lists
! List Protocol
MIXIN: list
-GENERIC: car ( cons -- car )
-GENERIC: cdr ( cons -- cdr )
-GENERIC: nil? ( object -- ? )
+GENERIC: car ( cons -- car )
+GENERIC: cdr ( cons -- cdr )
+GENERIC: nil? ( object -- ? )
-TUPLE: cons car cdr ;
+TUPLE: cons { car read-only } { cdr read-only } ;
C: cons cons
M: cons cdr ( cons -- cdr )
cdr>> ;
-
-SYMBOL: +nil+
-M: word nil? +nil+ eq? ;
+
+SINGLETON: +nil+
+M: +nil+ nil? drop t ;
M: object nil? drop f ;
-
-: atom? ( obj -- ? ) [ list? ] [ nil? ] bi or not ;
+
+: atom? ( obj -- ? )
+ { [ list? ] [ nil? ] } 1|| not ;
: nil ( -- symbol ) +nil+ ;
-
-: uncons ( cons -- cdr car )
- [ cdr ] [ car ] bi ;
-
+
+: uncons ( cons -- car cdr )
+ [ car ] [ cdr ] bi ;
+
+: swons ( cdr car -- cons )
+ swap cons ;
+
+: unswons ( cons -- cdr car )
+ uncons swap ;
+
: 1list ( obj -- cons )
nil cons ;
-
+
+: 1list? ( list -- ? )
+ { [ nil? not ] [ cdr nil? ] } 1&& ;
+
: 2list ( a b -- cons )
nil cons cons ;
: 3list ( a b c -- cons )
nil cons cons cons ;
-
-: cadr ( cons -- elt )
+
+: cadr ( list -- elt )
cdr car ;
-
-: 2car ( cons -- car caar )
+
+: 2car ( list -- car caar )
[ car ] [ cdr car ] bi ;
-
-: 3car ( cons -- car cadr caddr )
+
+: 3car ( list -- car cadr caddr )
[ car ] [ cdr car ] [ cdr cdr car ] tri ;
: lnth ( n list -- elt )
swap [ cdr ] times car ;
-
+
+<PRIVATE
: (leach) ( list quot -- cdr quot )
[ [ car ] dip call ] [ [ cdr ] dip ] 2bi ; inline
+PRIVATE>
: leach ( list quot: ( elt -- ) -- )
over nil? [ 2drop ] [ (leach) leach ] if ; inline recursive
: llength ( list -- n )
0 [ drop 1+ ] foldl ;
-
+
: lreverse ( list -- newlist )
nil [ swap cons ] foldl ;
-
+
: lappend ( list1 list2 -- newlist )
[ lreverse ] dip [ swap cons ] foldl ;
-
-: seq>list ( seq -- list )
+
+: lcut ( list index -- before after )
+ [ +nil+ ] dip
+ [ [ [ cdr ] [ car ] bi ] dip cons ] times
+ lreverse swap ;
+
+: sequence>cons ( sequence -- list )
<reversed> nil [ swap cons ] reduce ;
-
+
+<PRIVATE
: same? ( obj1 obj2 -- ? )
[ class ] bi@ = ;
-
-: seq>cons ( seq -- cons )
- [ <reversed> ] keep nil [ tuck same? [ seq>cons ] when f cons swap >>cdr ] with reduce ;
-
+PRIVATE>
+
+: deep-sequence>cons ( sequence -- cons )
+ [ <reversed> ] keep nil
+ [ tuck same? [ deep-sequence>cons ] when swons ] with reduce ;
+
+<PRIVATE
: (lmap>array) ( acc cons quot: ( elt -- elt' ) -- newcons )
over nil? [ 2drop ]
- [ [ uncons ] dip [ call ] keep swapd [ suffix ] 2dip (lmap>array) ] if ;
+ [ [ unswons ] dip [ call ] keep swapd [ suffix ] 2dip (lmap>array) ] if ;
inline recursive
-
-: lmap>array ( cons quot -- newcons )
- { } -rot (lmap>array) ; inline
-
-: lmap-as ( cons quot exemplar -- seq )
+PRIVATE>
+
+: lmap>array ( list quot -- array )
+ [ { } ] 2dip (lmap>array) ; inline
+
+: lmap-as ( list quot exemplar -- sequence )
[ lmap>array ] dip like ;
-
-: cons>seq ( cons -- array )
- [ dup cons? [ cons>seq ] when dup nil? [ drop { } ] when ] lmap>array ;
-
-: list>seq ( list -- array )
+
+: deep-list>array ( list -- array )
+ [
+ {
+ { [ dup list? ] [ deep-list>array ] }
+ { [ dup nil? ] [ drop { } ] }
+ [ ]
+ } cond
+ ] lmap>array ;
+
+: list>array ( list -- array )
[ ] lmap>array ;
-
+
: traverse ( list pred quot: ( list/elt -- result ) -- result )
- [ 2over call [ tuck [ call ] 2dip ] when
- pick list? [ traverse ] [ 2drop ] if ] 2curry lmap ; inline recursive
-
+ [
+ 2over call [ tuck [ call ] 2dip ] when
+ pick list? [ traverse ] [ 2drop ] if
+ ] 2curry lmap ; inline recursive
+
INSTANCE: cons list
+! Copyright (C) 2008 Daniel Ehrenberg
+! See http://factorcode.org/license.txt for BSD license.
USING: help.markup help.syntax kernel sequences ;
IN: persistent.deques
-! Copyback (C) 2008 Daniel Ehrenberg
+! Copyright (C) 2008 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors math lists ;
-QUALIFIED: sequences
+USING: kernel accessors math lists sequences combinators.short-circuit ;
IN: persistent.deques
! Amortized O(1) push/pop on both ends for single-threaded access
! same source, it could take O(m) amortized time per update.
<PRIVATE
-
-: each ( list quot: ( elt -- ) -- )
- over
- [ [ [ car ] dip call ] [ [ cdr ] dip ] 2bi each ]
- [ 2drop ] if ; inline recursive
-
-: reduce ( list start quot -- end )
- swapd each ; inline
-
-: reverse ( list -- reversed )
- f [ swap cons ] reduce ;
-
-: length ( list -- length )
- 0 [ drop 1+ ] reduce ;
-
-: cut ( list index -- back front-reversed )
- f swap [ [ [ cdr ] [ car ] bi ] dip cons ] times ;
-
: split-reverse ( list -- back-reversed front )
- dup length 2/ cut [ reverse ] bi@ ;
+ dup llength 2/ lcut lreverse swap ;
PRIVATE>
TUPLE: deque { front read-only } { back read-only } ;
-: <deque> ( -- deque ) T{ deque } ;
+: <deque> ( -- deque )
+ T{ deque f +nil+ +nil+ } ;
<PRIVATE
: flip ( deque -- newdeque )
PRIVATE>
: deque-empty? ( deque -- ? )
- [ front>> ] [ back>> ] bi or not ;
+ { [ front>> nil? ] [ back>> nil? ] } 1&& ;
<PRIVATE
: push ( item deque -- newdeque )
[ front>> car ] [ [ front>> cdr ] [ back>> ] bi deque boa ] bi ; inline
: transfer ( deque -- item newdeque )
- back>> [ split-reverse deque boa remove ]
- [ "Popping from an empty deque" throw ] if* ; inline
+ back>> dup nil?
+ [ "Popping from an empty deque" throw ]
+ [ split-reverse deque boa remove ] if ; inline
: pop ( deque -- item newdeque )
- dup front>> [ remove ] [ transfer ] if ; inline
+ dup front>> nil? [ transfer ] [ remove ] if ; inline
PRIVATE>
: pop-front ( deque -- item newdeque )
: pop-back ( deque -- item newdeque )
[ pop ] flipped ;
-: peek-front ( deque -- item ) pop-front drop ;
+: peek-front ( deque -- item )
+ pop-front drop ;
-: peek-back ( deque -- item ) pop-back drop ;
+: peek-back ( deque -- item )
+ pop-back drop ;
: sequence>deque ( sequence -- deque )
- <deque> [ push-back ] sequences:reduce ;
+ <deque> [ push-back ] reduce ;
: deque>sequence ( deque -- sequence )
- [ dup deque-empty? not ] [ pop-front swap ] [ ] sequences:produce nip ;
+ [ dup deque-empty? not ] [ pop-front swap ] [ ] produce nip ;
{ $notes "This word is used by " { $link >url } ". It can also be used directly to parse " { $snippet "host:port" } " strings which are not full URLs." }
{ $examples
{ $example
- "USING: prettyprint urls ;"
- "\"sbcl.org:80\" parse-host .s"
+ "USING: prettyprint urls kernel ;"
+ "\"sbcl.org:80\" parse-host .s 2drop"
"\"sbcl.org\"\n80"
}
} ;
: element-length ( element -- n )
[ black>> ] [ white>> ] bi + ;
-: swons ( cdr car -- cons )
- swap cons ;
-
-: unswons ( cons -- cdr car )
- [ cdr ] [ car ] bi ;
-
-: 1list? ( list -- ? )
- { [ ] [ cdr +nil+ = ] } 1&& ;
-
-: lists>arrays ( lists -- arrays )
- [ list>seq ] lmap>array ;
-
TUPLE: paragraph lines head-width tail-cost ;
C: <paragraph> paragraph
0 <paragraph> ;
: post-process ( paragraph -- array )
- lines>> lists>arrays
+ lines>> deep-list>array
[ [ contents>> ] map ] map ;
: initialize ( elements -- elements paragraph )
{ $description "Tests if " { $snippet "x" } " is an IEEE Infinity value. While " { $snippet "x" } " can be any real number, this word will only ever yield true if " { $snippet "x" } " is a " { $link float } "." }
{ $examples
{ $example "USING: math prettyprint ;" "1/0. fp-infinity? ." "t" }
- { $example "USING: io kernel math ;" "-1/0. [ fp-infinity? ] [ 0 < ] bi [ \"negative infinity\" print ] when" "negative infinity" }
+ { $example "USING: io kernel math ;" "-1/0. [ fp-infinity? ] [ 0 < ] bi and [ \"negative infinity\" print ] when" "negative infinity" }
} ;
{ fp-nan? fp-infinity? } related-words
: parse-1 ( input parser -- result )
dupd parse dup nil? [
- rot cannot-parse
+ swap cannot-parse
] [
nip car parsed>>
] if ;
PRIVATE>
: euler134 ( -- answer )
- 0 5 lprimes-from uncons swap [ 1000000 > ] luntil
+ 0 5 lprimes-from uncons [ 1000000 > ] luntil
[ [ s + ] keep ] leach drop ;
! [ euler134 ] 10 ave-time