"
COPYRIGHT (c) 2002 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
"{ Package: 'stx:libbasic2' }"
nil subclass:#LazyValue
instanceVariableNames:'result block'
classVariableNames:'AccessLock'
poolDictionaries:''
category:'Kernel-Processes'
!
!LazyValue class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 2002 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
I represent an expression which might not be needed.
Any messages sent to me will force the evaluation (once).
The value is remembered.
Can be used to simulate non-strict programming languages.
[see also:]
Block Future
[author:]
Claus Gittinger
"
!
examples
"
[exBegin]
|x|
x := LazyValue block:[ Transcript flash. 1234 ].
Delay waitForSeconds:4.
Transcript showCR:x printString
[exEnd]
listFrom:n - an infinite list of integers starting with n
[exBegin]
|gen infiniteList|
gen := [:n |
Cons
car:n
cdr:( LazyValue block:[gen value:n+1] )
].
infiniteList := gen value:1.
1 to:10 do:[:i |
Transcript showCR:infiniteList car.
infiniteList := infiniteList cdr.
].
[exEnd]
filterOdd:l - an infinite list filtering odd numbers from another list
[exBegin]
|gen infiniteList genOdd infiniteOdd|
gen := [:n |
Cons
car:n
cdr:( LazyValue block:[gen value:n+1] )
].
infiniteList := gen value:1.
genOdd := [:l |
|lR el|
lR := l.
[ el := lR car. lR := lR cdr. el odd ] whileFalse:[].
Cons
car:el
cdr:( LazyValue block:[genOdd value:lR] )
].
infiniteOdd := genOdd value:infiniteList.
1 to:10 do:[:i |
Transcript showCR:infiniteOdd car.
infiniteOdd := infiniteOdd cdr.
].
[exEnd]
powersOf:n - an infinite list of powers of n
[exBegin]
|genPowersOf infiniteListOfPowers|
genPowersOf := [:base |
|powersOfBase|
powersOfBase :=
[:n |
Cons
car:n
cdr:( LazyValue block:[powersOfBase value:n*base] )
].
powersOfBase value:1.
].
infiniteListOfPowers := genPowersOf value:2.
1 to:10 do:[:i |
Transcript showCR:infiniteListOfPowers car.
infiniteListOfPowers := infiniteListOfPowers cdr.
].
[exEnd]
merge2:a _:b - merge 2 lists.
[exBegin]
|genMerge2 l gen infiniteList genOdd infiniteOdd genEven infiniteEven genMerge|
gen := [:n |
Cons
car:n
cdr:( LazyValue block:[gen value:n+1] )
].
infiniteList := gen value:1.
genOdd := [:l |
|lR el|
lR := l.
[ el := lR car. lR := lR cdr. el odd ] whileFalse:[].
Cons
car:el
cdr:( LazyValue block:[genOdd value:lR] )
].
infiniteOdd := genOdd value:infiniteList.
genEven := [:l |
|lR el|
lR := l.
[ el := lR car. lR := lR cdr. el even ] whileFalse:[].
Cons
car:el
cdr:( LazyValue block:[genEven value:lR] )
].
infiniteEven := genEven value:infiniteList.
genMerge2 := [:a :b |
|nextA nextB|
nextA := a car.
nextB := b car.
nextA < nextB ifTrue:[
Cons
car:nextA
cdr:( LazyValue block:[genMerge2 value:(a cdr) value:b] )
] ifFalse:[
Cons
car:nextB
cdr:( LazyValue block:[genMerge2 value:a value:(b cdr)] )
].
].
l := genMerge2 value:infiniteOdd value:infiniteEven.
1 to:10 do:[:i |
Transcript showCR:l car.
l := l cdr.
].
[exEnd]
genPoly - generate 2^i + 3^j + 5^k for all i,j,k
not finished.
[exBegin]
|genMerge2 l gen genPowersOf infiniteList powersOf2 powersOf3 powersOf5|
gen := [:n |
Cons
car:n
cdr:( LazyValue block:[gen value:n+1] )
].
infiniteList := gen value:1.
genPowersOf := [:base |
|powersOfBase|
powersOfBase :=
[:n |
Cons
car:n
cdr:( LazyValue block:[powersOfBase value:n*base] )
].
powersOfBase value:1.
].
powersOf2 := genPowersOf value:2.
powersOf3 := genPowersOf value:3.
powersOf5 := genPowersOf value:5.
genAdd := [:n :l |
|gen|
gen := [:l |
Cons
car:(car l) * n
cdr:( LazyValue block:[gen value:(l cdr)] )
].
gen value:l
].
genMerge2 := [:a :b |
|min nextA nextB rA rB|
rA := a.
rB := b.
nextA := rA car.
[ (nextB := rB car) = nextA ] whileTrue:[ rB := rB cdr ].
nextA < nextB ifTrue:[
'a is smallest'.
min := nextA.
rA := rA cdr.
] ifFalse:[
'b is smallest'.
min := nextB.
rB := rB cdr.
].
Cons
car:min
cdr:( LazyValue block:[genMerge2 value:rA value:rB] )
].
l := genMerge2 value:powersOf2 value:powersOf3 value:powersOf5.
1 to:10 do:[:i |
Transcript showCR:l car.
l := l cdr.
].
[exEnd]
"
! !
!LazyValue class methodsFor:'initialization'!
initialize
AccessLock := RecursionLock forMutualExclusion
! !
!LazyValue class methodsFor:'instance creation'!
block:aBlock
^ self new block:aBlock
! !
!LazyValue methodsFor:'error handling'!
doesNotUnderstand:aMessage
block notNil ifTrue:[
self _evaluate_
].
^ aMessage sendTo:result
! !
!LazyValue methodsFor:'evaluation'!
_evaluate_
block notNil ifTrue:[
AccessLock critical:[
|b|
(b := block) notNil ifTrue:[
block := nil.
result := b value.
].
].
].
^ result
! !
!LazyValue methodsFor:'printing'!
displayString
block isNil ifTrue:[
^ 'LazyValue (unevaluated)'
].
^ 'LazyValue (evaluated)'
!
printOn:aStream
aStream nextPutAll:'(lazy)'
! !
!LazyValue methodsFor:'private access'!
block:aBlock
block := aBlock.
! !
!LazyValue methodsFor:'queries'!
class
^ self _evaluate_ class
!
isLazyValue
^ block notNil
! !
!LazyValue methodsFor:'testing'!
isBehavior
^ self _evaluate_ isBehavior
! !
!LazyValue class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libbasic2/LazyValue.st,v 1.2 2002-07-25 14:38:51 cg Exp $'
! !
LazyValue initialize!