Hi Gregg,
>
> You have to know about the internal "emit" word, or add it as an
> arg, to avoid conflict. Have to watch not to conflict with OUT as
> well. Hmmm, the other one has the same problem with 'dst doesn't it?
>
No.
> Ladislav, is there a reason you don't reuse 'dest, rather than
> creating 'dst?
Just the fact, that it would be inconvenient, because use [dest]
copy/deep [...] hides the original DEST argument. You may ask why we
need use [dest] copy/deep [...]. My answer is, that it is there to make
the COLLECT function reentrant (to pass my reentrancy test below). The
reasons are described in the "Computed Binding Functions (Closures)"
section of http://www.fm.tul.cz/~ladislav/rebol/contexts.html .
We can reuse the DEST variable using the following trick, though:
do func [dest] [...] :dest
the implementation might look as follows, then:
collect: func [
{Collects values, returning them as a series.}
[throw]
emit [word!] "Word used to collect values"
block [block!] "Block to evaluate"
/into dest [series!] "Where to append results"
/only "Insert series values as series"
/local ins
] [
; Create a new context containing just one word (the EMIT
; argument) and set the 'emit word to refer to the new context
; word. Note the care taken to suppress possible conflicts and
; undesired evaluations.
emit: reduce [emit]
emit: first use emit reduce [emit]
do func [dest] [
; make the function used to collect values.
ins: either only [[insert/only]] [[insert]]
set emit func [value [any-type!]] compose [
(ins) tail :dest get/any 'value
get/any 'value
]
do bind/copy block emit
head :dest
] any [:dest copy []]
]
Another option is to use a closure (
http://www.fm.tul.cz/~ladislav/rebol/closure.r , which is going to be
implemented natively in R3) and the implementation may be: (see, what
are the closures good for?)
collect: closure [
{Collects values, returning them as a series.}
[throw]
emit [word!] "Word used to collect values"
block [block!] "Block to evaluate"
/into dest [series!] "Where to append results"
/only "Insert series values as series"
/local ins
] [
; Create a new context containing just one word (the EMIT
; argument) and set the 'emit word to refer to the new context
; word. Note the care taken to suppress possible conflicts and
; undesired evaluations.
emit: reduce [emit]
emit: first use emit reduce [emit]
dest: any [:dest []]
; make the function used to collect values.
ins: either only [[insert/only]] [[insert]]
set emit func [value [any-type!]] compose [
(ins) tail :dest get/any 'value
get/any 'value
]
do bind/copy block emit
head :dest
]
; test:
probe collect 'x [
probe collect 'y [
foreach i [1 2] [
y negate i
x i
]
]
]
> And you could still mess things up, right (by
> using dest/dst as a set-word! in the block?
>
Not at all, don't worry. It does not have anything in common with the
contents of the BLOCK argument.
>
> Are there other REBOL funcs that work similarly?
>
> Would we want to create shortcuts, like FUNC/HAS/DOES?
>
> Thanks for posting Volker, the more we think about this, the better it
> will eventually be.
>
> -- Gregg
>
-L
--
To unsubscribe from the list, just send an email to
lists at rebol.com with unsubscribe as the subject.