Making lazy lists compile, and using them where applicable

db4
Daniel Ehrenberg 2009-02-08 23:06:03 -06:00
parent af9f5112d4
commit c4aa14b9d9
8 changed files with 125 additions and 141 deletions

View File

@ -1,6 +1,6 @@
! Copyback (C) 2008 Daniel Ehrenberg ! Copyback (C) 2008 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors math ; USING: kernel accessors math lists ;
QUALIFIED: sequences QUALIFIED: sequences
IN: persistent.deques IN: persistent.deques
@ -9,25 +9,23 @@ IN: persistent.deques
! same source, it could take O(m) amortized time per update. ! same source, it could take O(m) amortized time per update.
<PRIVATE <PRIVATE
TUPLE: cons { car read-only } { cdr read-only } ;
C: <cons> cons
: each ( list quot: ( elt -- ) -- ) : each ( list quot: ( elt -- ) -- )
over over
[ [ [ car>> ] dip call ] [ [ cdr>> ] dip ] 2bi each ] [ [ [ car ] dip call ] [ [ cdr ] dip ] 2bi each ]
[ 2drop ] if ; inline recursive [ 2drop ] if ; inline recursive
: reduce ( list start quot -- end ) : reduce ( list start quot -- end )
swapd each ; inline swapd each ; inline
: reverse ( list -- reversed ) : reverse ( list -- reversed )
f [ swap <cons> ] reduce ; f [ swap cons ] reduce ;
: length ( list -- length ) : length ( list -- length )
0 [ drop 1+ ] reduce ; 0 [ drop 1+ ] reduce ;
: cut ( list index -- back front-reversed ) : cut ( list index -- back front-reversed )
f swap [ [ [ cdr>> ] [ car>> ] bi ] dip <cons> ] times ; f swap [ [ [ cdr ] [ car ] bi ] dip cons ] times ;
: split-reverse ( list -- back-reversed front ) : split-reverse ( list -- back-reversed front )
dup length 2/ cut [ reverse ] bi@ ; dup length 2/ cut [ reverse ] bi@ ;
@ -49,7 +47,7 @@ PRIVATE>
<PRIVATE <PRIVATE
: push ( item deque -- newdeque ) : push ( item deque -- newdeque )
[ front>> <cons> ] [ back>> ] bi deque boa ; inline [ front>> cons ] [ back>> ] bi deque boa ; inline
PRIVATE> PRIVATE>
: push-front ( deque item -- newdeque ) : push-front ( deque item -- newdeque )
@ -60,7 +58,7 @@ PRIVATE>
<PRIVATE <PRIVATE
: remove ( deque -- item newdeque ) : remove ( deque -- item newdeque )
[ front>> car>> ] [ [ front>> cdr>> ] [ back>> ] bi deque boa ] bi ; inline [ front>> car ] [ [ front>> cdr ] [ back>> ] bi deque boa ] bi ; inline
: transfer ( deque -- item newdeque ) : transfer ( deque -- item newdeque )
back>> [ split-reverse deque boa remove ] back>> [ split-reverse deque boa remove ]

View File

@ -10,10 +10,10 @@ ARTICLE: "wrap" "Word wrapping"
{ $subsection wrap-lines } { $subsection wrap-lines }
{ $subsection wrap-string } { $subsection wrap-string }
{ $subsection wrap-indented-string } { $subsection wrap-indented-string }
"Additionally, the vocabulary provides capabilities to wrap arbitrary groups of things, in units called elements." "Additionally, the vocabulary provides capabilities to wrap arbitrary groups of things, in units called segments."
{ $subsection wrap-elements } { $subsection wrap-segments }
{ $subsection element } { $subsection segment }
{ $subsection <element> } ; { $subsection <segment> } ;
HELP: wrap-lines HELP: wrap-lines
{ $values { "lines" string } { "width" integer } { "newlines" "sequence of strings" } } { $values { "lines" string } { "width" integer } { "newlines" "sequence of strings" } }
@ -27,15 +27,15 @@ HELP: wrap-indented-string
{ $values { "string" string } { "width" integer } { "indent" string } { "newstring" string } } { $values { "string" string } { "width" integer } { "indent" string } { "newstring" string } }
{ $description "Given a string, alters the whitespace in the string so that each line has no more than " { $snippet "width" } " characters, unless there is a word longer than " { $snippet "width" } ". Linear whitespace between words is converted to a single space. Before each line, the indent string is added." } ; { $description "Given a string, alters the whitespace in the string so that each line has no more than " { $snippet "width" } " characters, unless there is a word longer than " { $snippet "width" } ". Linear whitespace between words is converted to a single space. Before each line, the indent string is added." } ;
HELP: wrap-elements HELP: wrap-segments
{ $values { "elements" { "a sequence of " { $instance element } "s" } } { "line-max" integer } { "line-ideal" integer } { "lines" "a sequence of sequences of words" } } { $values { "segments" { "a sequence of " { $instance segment } "s" } } { "line-max" integer } { "line-ideal" integer } { "lines" "a sequence of sequences of words" } }
{ $description "Divides the words into lines, where the sum of the lengths of the words on a line (not counting breaks at the end of the line) is at most the given maximum. The returned set of lines is optimized to minimize the square of the deviation of each line from the ideal width. It is not guaranteed to be the minimal number of lines. Every line except for the first one starts with a non-break, and every one but the last ends with a break." } ; { $description "Divides the words into lines, where the sum of the lengths of the words on a line (not counting breaks at the end of the line) is at most the given maximum. The returned set of lines is optimized to minimize the square of the deviation of each line from the ideal width. It is not guaranteed to be the minimal number of lines. Every line except for the first one starts with a non-break, and every one but the last ends with a break." } ;
HELP: element HELP: segment
{ $class-description "An element is a Factor object annotated with a length (in the " { $snippet "width" } " slot) and knowledge about whether it is an allowable position for an optional line break (in the " { $snippet "break?" } " slot). Elements can be created with " { $link <element> } "." } { $class-description "A segment is a Factor object annotated with a length (in the " { $snippet "width" } " slot) and knowledge about whether it is an allowable position for an optional line break (in the " { $snippet "break?" } " slot). Elements can be created with " { $link <segment> } "." }
{ $see-also wrap-elements } ; { $see-also wrap-segments } ;
HELP: <element> HELP: <segment>
{ $values { "key" object } { "width" integer } { "break?" { { $link t } " or " { $link POSTPONE: f } } } { "element" element } } { $values { "key" object } { "width" integer } { "break?" { { $link t } " or " { $link POSTPONE: f } } } { "segment" segment } }
{ $description "Creates an " { $link element } " object with the given parameters." } { $description "Creates a " { $link segment } " object with the given parameters." }
{ $see-also wrap-elements } ; { $see-also wrap-segments } ;

View File

@ -6,77 +6,77 @@ IN: wrap.tests
[ [
{ {
{ {
T{ element f 1 10 f } T{ segment f 1 10 f }
T{ element f 2 10 f } T{ segment f 2 10 f }
T{ element f 3 2 t } T{ segment f 3 2 t }
} }
{ {
T{ element f 4 10 f } T{ segment f 4 10 f }
T{ element f 5 10 f } T{ segment f 5 10 f }
} }
} }
] [ ] [
{ {
T{ element f 1 10 f } T{ segment f 1 10 f }
T{ element f 2 10 f } T{ segment f 2 10 f }
T{ element f 3 2 t } T{ segment f 3 2 t }
T{ element f 4 10 f } T{ segment f 4 10 f }
T{ element f 5 10 f } T{ segment f 5 10 f }
} 35 35 wrap-elements [ { } like ] map } 35 35 wrap-segments [ { } like ] map
] unit-test ] unit-test
[ [
{ {
{ {
T{ element f 1 10 f } T{ segment f 1 10 f }
T{ element f 2 10 f } T{ segment f 2 10 f }
T{ element f 3 9 t } T{ segment f 3 9 t }
T{ element f 3 9 t } T{ segment f 3 9 t }
T{ element f 3 9 t } T{ segment f 3 9 t }
} }
{ {
T{ element f 4 10 f } T{ segment f 4 10 f }
T{ element f 5 10 f } T{ segment f 5 10 f }
} }
} }
] [ ] [
{ {
T{ element f 1 10 f } T{ segment f 1 10 f }
T{ element f 2 10 f } T{ segment f 2 10 f }
T{ element f 3 9 t } T{ segment f 3 9 t }
T{ element f 3 9 t } T{ segment f 3 9 t }
T{ element f 3 9 t } T{ segment f 3 9 t }
T{ element f 4 10 f } T{ segment f 4 10 f }
T{ element f 5 10 f } T{ segment f 5 10 f }
} 35 35 wrap-elements [ { } like ] map } 35 35 wrap-segments [ { } like ] map
] unit-test ] unit-test
[ [
{ {
{ {
T{ element f 1 10 t } T{ segment f 1 10 t }
T{ element f 1 10 f } T{ segment f 1 10 f }
T{ element f 3 9 t } T{ segment f 3 9 t }
} }
{ {
T{ element f 2 10 f } T{ segment f 2 10 f }
T{ element f 3 9 t } T{ segment f 3 9 t }
} }
{ {
T{ element f 4 10 f } T{ segment f 4 10 f }
T{ element f 5 10 f } T{ segment f 5 10 f }
} }
} }
] [ ] [
{ {
T{ element f 1 10 t } T{ segment f 1 10 t }
T{ element f 1 10 f } T{ segment f 1 10 f }
T{ element f 3 9 t } T{ segment f 3 9 t }
T{ element f 2 10 f } T{ segment f 2 10 f }
T{ element f 3 9 t } T{ segment f 3 9 t }
T{ element f 4 10 f } T{ segment f 4 10 f }
T{ element f 5 10 f } T{ segment f 5 10 f }
} 35 35 wrap-elements [ { } like ] map } 35 35 wrap-segments [ { } like ] map
] unit-test ] unit-test
[ [
@ -115,4 +115,4 @@ word wrap.">
[ "aaa bb\nccccccc\nddddddd" ] [ "aaa bb ccccccc ddddddd" 6 wrap-string ] unit-test [ "aaa bb\nccccccc\nddddddd" ] [ "aaa bb ccccccc ddddddd" 6 wrap-string ] unit-test
\ wrap-string must-infer \ wrap-string must-infer
\ wrap-elements must-infer \ wrap-segments must-infer

View File

@ -1,39 +1,28 @@
USING: kernel sequences math arrays locals fry accessors splitting USING: kernel sequences math arrays locals fry accessors
make combinators.short-circuit namespaces grouping splitting.monotonic ; lists splitting call make combinators.short-circuit namespaces
grouping splitting.monotonic ;
IN: wrap IN: wrap
<PRIVATE <PRIVATE
! black is the text length, white is the whitespace length ! black is the text length, white is the whitespace length
TUPLE: word contents black white ; TUPLE: element contents black white ;
C: <word> word C: <element> element
: word-length ( word -- n ) : element-length ( element -- n )
[ black>> ] [ white>> ] bi + ; [ black>> ] [ white>> ] bi + ;
TUPLE: cons cdr car ; ! This order works out better : swons ( cdr car -- cons )
C: <cons> cons swap cons ;
: >cons< ( cons -- cdr car ) : unswons ( cons -- cdr car )
[ cdr>> ] [ car>> ] bi ; [ cdr ] [ car ] bi ;
: list-each ( list quot -- ) : 1list? ( list -- ? )
over [ { [ ] [ cdr +nil+ = ] } 1&& ;
[ [ car>> ] dip call ]
[ [ cdr>> ] dip list-each ] 2bi
] [ 2drop ] if ; inline recursive
: singleton? ( list -- ? )
{ [ ] [ cdr>> not ] } 1&& ;
: <singleton> ( elt -- list )
f swap <cons> ;
: list>array ( list -- array )
[ [ , ] list-each ] { } make ;
: lists>arrays ( lists -- arrays ) : lists>arrays ( lists -- arrays )
[ [ list>array , ] list-each ] { } make ; [ list>seq ] lmap>array ;
TUPLE: paragraph lines head-width tail-cost ; TUPLE: paragraph lines head-width tail-cost ;
C: <paragraph> paragraph C: <paragraph> paragraph
@ -46,11 +35,11 @@ SYMBOL: line-ideal
: top-fits? ( paragraph -- ? ) : top-fits? ( paragraph -- ? )
[ head-width>> ] [ head-width>> ]
[ lines>> singleton? line-ideal line-max ? get ] bi <= ; [ lines>> 1list? line-ideal line-max ? get ] bi <= ;
: fits? ( paragraph -- ? ) : fits? ( paragraph -- ? )
! Make this not count spaces at end ! Make this not count spaces at end
{ [ lines>> car>> singleton? ] [ top-fits? ] } 1|| ; { [ lines>> car 1list? ] [ top-fits? ] } 1|| ;
:: min-by ( seq quot -- elt ) :: min-by ( seq quot -- elt )
f 1.0/0.0 seq [| key value new | f 1.0/0.0 seq [| key value new |
@ -65,26 +54,26 @@ SYMBOL: line-ideal
: min-cost ( paragraphs -- paragraph ) : min-cost ( paragraphs -- paragraph )
[ paragraph-cost ] min-by ; [ paragraph-cost ] min-by ;
: new-line ( paragraph word -- paragraph ) : new-line ( paragraph element -- paragraph )
[ [ lines>> ] [ <singleton> ] bi* <cons> ] [ [ lines>> ] [ 1list ] bi* swons ]
[ nip black>> ] [ nip black>> ]
[ drop paragraph-cost ] 2tri [ drop paragraph-cost ] 2tri
<paragraph> ; <paragraph> ;
: glue ( paragraph word -- paragraph ) : glue ( paragraph element -- paragraph )
[ [ lines>> >cons< ] dip <cons> <cons> ] [ [ lines>> unswons ] dip swons swons ]
[ [ head-width>> ] [ word-length ] bi* + ] [ [ head-width>> ] [ element-length ] bi* + ]
[ drop tail-cost>> ] 2tri [ drop tail-cost>> ] 2tri
<paragraph> ; <paragraph> ;
: wrap-step ( paragraphs word -- paragraphs ) : wrap-step ( paragraphs element -- paragraphs )
[ '[ _ glue ] map ] [ '[ _ glue ] map ]
[ [ min-cost ] dip new-line ] [ [ min-cost ] dip new-line ]
2bi prefix 2bi prefix
[ fits? ] filter ; [ fits? ] filter ;
: 1paragraph ( word -- paragraph ) : 1paragraph ( element -- paragraph )
[ <singleton> <singleton> ] [ 1list 1list ]
[ black>> ] bi [ black>> ] bi
0 <paragraph> ; 0 <paragraph> ;
@ -92,10 +81,10 @@ SYMBOL: line-ideal
lines>> lists>arrays lines>> lists>arrays
[ [ contents>> ] map ] map ; [ [ contents>> ] map ] map ;
: initialize ( words -- words paragraph ) : initialize ( elements -- elements paragraph )
<reversed> unclip-slice 1paragraph 1array ; <reversed> unclip-slice 1paragraph 1array ;
: wrap ( words line-max line-ideal -- paragraph ) : wrap ( elements line-max line-ideal -- paragraph )
[ [
line-ideal set line-ideal set
line-max set line-max set
@ -107,50 +96,50 @@ SYMBOL: line-ideal
PRIVATE> PRIVATE>
TUPLE: element key width break? ; TUPLE: segment key width break? ;
C: <element> element C: <segment> segment
<PRIVATE <PRIVATE
: elements-length ( elements -- length ) : segments-length ( segments -- length )
[ width>> ] map sum ; [ width>> ] map sum ;
: make-word ( whites blacks -- word ) : make-element ( whites blacks -- element )
[ append ] [ [ elements-length ] bi@ ] 2bi <word> ; [ append ] [ [ segments-length ] bi@ ] 2bi <element> ;
: ?first2 ( seq -- first/f second/f ) : ?first2 ( seq -- first/f second/f )
[ 0 swap ?nth ] [ 0 swap ?nth ]
[ 1 swap ?nth ] bi ; [ 1 swap ?nth ] bi ;
: split-elements ( seq -- half-words ) : split-segments ( seq -- half-elements )
[ [ break?>> ] bi@ = ] monotonic-split ; [ [ break?>> ] bi@ = ] monotonic-split ;
: ?first-break ( seq -- newseq f/word ) : ?first-break ( seq -- newseq f/element )
dup first first break?>> dup first first break?>>
[ unclip-slice f swap make-word ] [ unclip-slice f swap make-element ]
[ f ] if ; [ f ] if ;
: make-words ( seq f/word -- words ) : make-elements ( seq f/element -- elements )
[ 2 <groups> [ ?first2 make-word ] map ] dip [ 2 <groups> [ ?first2 make-element ] map ] dip
[ prefix ] when* ; [ prefix ] when* ;
: elements>words ( seq -- newseq ) : segments>elements ( seq -- newseq )
split-elements ?first-break make-words ; split-segments ?first-break make-elements ;
PRIVATE> PRIVATE>
: wrap-elements ( elements line-max line-ideal -- lines ) : wrap-segments ( segments line-max line-ideal -- lines )
[ elements>words ] 2dip wrap [ concat ] map ; [ segments>elements ] 2dip wrap [ concat ] map ;
<PRIVATE <PRIVATE
: split-lines ( string -- words-lines ) : split-lines ( string -- elements-lines )
string-lines [ string-lines [
" \t" split harvest " \t" split harvest
[ dup length 1 <word> ] map [ dup length 1 <element> ] map
] map ; ] map ;
: join-words ( wrapped-lines -- lines ) : join-elements ( wrapped-lines -- lines )
[ " " join ] map ; [ " " join ] map ;
: join-lines ( strings -- string ) : join-lines ( strings -- string )
@ -159,7 +148,7 @@ PRIVATE>
PRIVATE> PRIVATE>
: wrap-lines ( lines width -- newlines ) : wrap-lines ( lines width -- newlines )
[ split-lines ] dip '[ _ dup wrap join-words ] map concat ; [ split-lines ] dip '[ _ dup wrap join-elements ] map concat ;
: wrap-string ( string width -- newstring ) : wrap-string ( string width -- newstring )
wrap-lines join-lines ; wrap-lines join-lines ;

View File

@ -1,6 +1,5 @@
! Copyright (C) 2006 Matthew Willis and Chris Double. ! Copyright (C) 2006 Matthew Willis and Chris Double.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
!
USING: lists lists.lazy tools.test kernel math io sequences ; USING: lists lists.lazy tools.test kernel math io sequences ;
IN: lists.lazy.tests IN: lists.lazy.tests
@ -27,3 +26,10 @@ IN: lists.lazy.tests
[ { 4 5 6 } ] [ [ { 4 5 6 } ] [
3 { 1 2 3 } >list [ + ] lazy-map-with list>array 3 { 1 2 3 } >list [ + ] lazy-map-with list>array
] unit-test ] unit-test
[ [ ] lmap ] must-infer
[ [ ] lmap>array ] must-infer
[ [ drop ] foldr ] must-infer
[ [ drop ] foldl ] must-infer
[ [ drop ] leach ] must-infer
[ lnth ] must-infer

View File

@ -1,12 +1,7 @@
! Copyright (C) 2004 Chris Double. ! Copyright (C) 2004, 2008 Chris Double, Matthew Willis, James Cash.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
!
! Updated by Matthew Willis, July 2006
! Updated by Chris Double, September 2006
! Updated by James Cash, June 2008
!
USING: kernel sequences math vectors arrays namespaces make USING: kernel sequences math vectors arrays namespaces make
quotations promises combinators io lists accessors ; quotations promises combinators io lists accessors call ;
IN: lists.lazy IN: lists.lazy
M: promise car ( promise -- car ) M: promise car ( promise -- car )
@ -86,7 +81,7 @@ C: <lazy-map> lazy-map
M: lazy-map car ( lazy-map -- car ) M: lazy-map car ( lazy-map -- car )
[ cons>> car ] keep [ cons>> car ] keep
quot>> call ; quot>> call( old -- new ) ;
M: lazy-map cdr ( lazy-map -- cdr ) M: lazy-map cdr ( lazy-map -- cdr )
[ cons>> cdr ] keep [ cons>> cdr ] keep
@ -130,7 +125,7 @@ M: lazy-until car ( lazy-until -- car )
cons>> car ; cons>> car ;
M: lazy-until cdr ( lazy-until -- cdr ) M: lazy-until cdr ( lazy-until -- cdr )
[ cons>> uncons ] keep quot>> tuck call [ cons>> uncons ] keep quot>> tuck call( elt -- ? )
[ 2drop nil ] [ luntil ] if ; [ 2drop nil ] [ luntil ] if ;
M: lazy-until nil? ( lazy-until -- bool ) M: lazy-until nil? ( lazy-until -- bool )
@ -150,7 +145,7 @@ M: lazy-while cdr ( lazy-while -- cdr )
[ cons>> cdr ] keep quot>> lwhile ; [ cons>> cdr ] keep quot>> lwhile ;
M: lazy-while nil? ( lazy-while -- bool ) M: lazy-while nil? ( lazy-while -- bool )
[ car ] keep quot>> call not ; [ car ] keep quot>> call( elt -- ? ) not ;
TUPLE: lazy-filter cons quot ; TUPLE: lazy-filter cons quot ;
@ -160,7 +155,7 @@ C: <lazy-filter> lazy-filter
over nil? [ 2drop nil ] [ <lazy-filter> <memoized-cons> ] if ; over nil? [ 2drop nil ] [ <lazy-filter> <memoized-cons> ] if ;
: car-filter? ( lazy-filter -- ? ) : car-filter? ( lazy-filter -- ? )
[ cons>> car ] [ quot>> ] bi call ; [ cons>> car ] [ quot>> ] bi call( elt -- ? ) ;
: skip ( lazy-filter -- ) : skip ( lazy-filter -- )
dup cons>> cdr >>cons drop ; dup cons>> cdr >>cons drop ;
@ -221,7 +216,7 @@ M: lazy-from-by car ( lazy-from-by -- car )
M: lazy-from-by cdr ( lazy-from-by -- cdr ) M: lazy-from-by cdr ( lazy-from-by -- cdr )
[ n>> ] keep [ n>> ] keep
quot>> dup slip lfrom-by ; quot>> [ call( old -- new ) ] keep lfrom-by ;
M: lazy-from-by nil? ( lazy-from-by -- bool ) M: lazy-from-by nil? ( lazy-from-by -- bool )
drop f ; drop f ;
@ -355,7 +350,8 @@ M: lazy-io car ( lazy-io -- car )
dup car>> dup [ dup car>> dup [
nip nip
] [ ] [
drop dup stream>> over quot>> call drop dup stream>> over quot>>
call( stream -- value )
>>car >>car
] if ; ] if ;

View File

@ -1,7 +1,6 @@
! Copyright (C) 2008 James Cash ! Copyright (C) 2008 James Cash
! See http://factorcode.org/license.txt for BSD license. ! 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 locals ;
IN: lists IN: lists
! List Protocol ! List Protocol
@ -46,7 +45,7 @@ M: object nil? drop f ;
: 2car ( cons -- car caar ) : 2car ( cons -- car caar )
[ car ] [ cdr car ] bi ; [ car ] [ cdr car ] bi ;
: 3car ( cons -- car caar caaar ) : 3car ( cons -- car cadr caddr )
[ car ] [ cdr car ] [ cdr cdr car ] tri ; [ car ] [ cdr car ] [ cdr cdr car ] tri ;
: lnth ( n list -- elt ) : lnth ( n list -- elt )
@ -109,4 +108,4 @@ M: object nil? drop f ;
[ 2over call [ tuck [ call ] 2dip ] when [ 2over call [ tuck [ call ] 2dip ] when
pick list? [ traverse ] [ 2drop ] if ] 2curry lmap ; inline recursive pick list? [ traverse ] [ 2drop ] if ] 2curry lmap ; inline recursive
INSTANCE: cons list INSTANCE: cons list

View File

@ -1,10 +1,6 @@
! Copyright (C) 2004 Chris Double. ! Copyright (C) 2004, 2006 Chris Double, Matthew Willis.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
! USING: arrays kernel sequences math vectors arrays namespaces call
! Updated by Matthew Willis, July 2006
! Updated by Chris Double, September 2006
USING: arrays kernel sequences math vectors arrays namespaces
make quotations parser effects stack-checker words accessors ; make quotations parser effects stack-checker words accessors ;
IN: promises IN: promises
@ -24,7 +20,7 @@ TUPLE: promise quot forced? value ;
#! promises quotation on the stack. Re-forcing the promise #! promises quotation on the stack. Re-forcing the promise
#! will return the same value and not recall the quotation. #! will return the same value and not recall the quotation.
dup forced?>> [ dup forced?>> [
dup quot>> call >>value dup quot>> call( -- value ) >>value
t >>forced? t >>forced?
] unless ] unless
value>> ; value>> ;