COLLECTing results
[1/29] from: brett::codeconscious::com at: 24-Jul-2003 15:44
While developing various versions of Map related functions I had cause to
pause and wonder if I could be more orthogonal with the functionality.
As background, the the main benefit of the Map function is collecting
function results in a block. I felt that my shortcut method method of using
a block to specify the mapping function was neat and followed other Rebol
functions. The shortcut method is used by Repeat, Foreach etc to specify the
body block - so could just add collection of the results? Yes!
So here is Collect - the sole purpose of which is to collect the evaluation
of a result. I haven't thorougly tested it so I've no idea how it will go in
memory usage/garbage collection.
>> repeat i 10 collect [i]
== [1 2 3 4 5 6 7 8 9 10]
>> foreach [a b] [1 2 3 4] collect [a + b]
== [3 7]
collect: func [
{Collects block evaluations, use with For, Repeat, etc.}
block [block!]
/init result "Initialise the result series."
/only "Inserts into result using Only refinement."
] [
if empty? block [return block]
compose [
result: any [result make block! 100]
(pick [insert/only insert] found? only) tail result (block)
result
]
]
Regards,
Brett
---
Website: http://www.codeconscious.com
Rebsite: http://www.codeconscious.com/index.r
[2/29] from: brett:codeconscious at: 24-Jul-2003 16:12
Oops silly mistake. Forgot the DO.
collect: func [
{Collects block evaluations, use with For, Repeat, etc.}
block [block!]
/init result "Initialise the result series."
/only "Inserts into result using Only refinement."
] [
if empty? block [return block]
compose/deep [
result: any [result make block! 100]
(pick [insert insert/only] not only) tail result do [(block)]
result
]
]
I wonder if filtering can be added in a similar way?
P.S Andrew: thanks for the tip regarding the "not only".
Regards,
Brett.
[3/29] from: AJMartin:orcon at: 24-Jul-2003 18:32
> >> foreach [a b] [1 2 3 4] collect [a + b]
> == [3 7]
Unfortunately, it fails in this case:
>> foreach [a b] [1 2 3 4] collect [print a print b a + b]
1
2
3
4
== [unset unset]
But this version:
>> collect: func [
[ {Collects block evaluations, use with For, Repeat, etc.}
[ block [block!]
[ /init result "Initialise the result series."
[ /only "Inserts into result using Only refinement."
[ ] [
[ if empty? block [return block]
[ compose/deep [
[ result: any [result make block! 100]
[ (pick [insert/only insert] found? only) tail result do
[(block)]
[ result
[ ]
[ ]
...works bettter:
>> foreach [a b] [1 2 3 4] collect [print a print b a + b]
1
2
3
4
== [3 7]
:)
Note:
compose/deep
and:
do [(block)]
Andrew J Martin
ICQ: 26227169 http://www.rebol.it/Valley/ http://Valley.150m.com/
[4/29] from: AJMartin:orcon at: 24-Jul-2003 18:51
Brett wrote:
> P.S Andrew: thanks for the tip regarding the "not only".
No problem! :)
I've got this for my version of 'Collect:
>> source Collect
Collect: func [
"Collects the results of block evaluations."
Block [block!] "The block to 'do."
/Only "Inserts the result as a series." /local
Results][
Results: copy []
compose/deep/only [
head (pick [insert insert/only] not Only) tail Results do (Block)
]
]
I think filtering could be just a word! (or a path!) between 'Collect and
the block! value.
Andrew J Martin
Writing in Orthodocs Rebol...
ICQ: 26227169 http://www.rebol.it/Valley/ http://Valley.150m.com/
[5/29] from: g:santilli:tiscalinet:it at: 24-Jul-2003 9:57
Hi Brett,
On Thursday, July 24, 2003, 7:44:19 AM, you wrote:
BH> collect: func [
BH> {Collects block evaluations, use with For, Repeat, etc.}
BH> block [block!]
BH> /init result "Initialise the result series."
BH> /only "Inserts into result using Only refinement."
BH> ] [
BH> if empty? block [return block]
BH> compose [
BH> result: any [result make block! 100]
BH> (pick [insert/only insert] found? only) tail result (block)
BH> result
BH> ]
BH> ]
Small note: you should bind your RESULT word to a fresh context
(USE, etc.), otherwise you'll be relying on COLLECT's context not
being modified while the body block is getting evaluated.
Anyway, this is a great idea!
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[6/29] from: nitsch-lists:netcologne at: 24-Jul-2003 10:19
Cool func.
regarding filtering: there is 'remove-each
remove-each item copy block [..]
works like a filter. some memory for copy, but then native.
-Volker
Am Donnerstag, 24. Juli 2003 08:12 schrieb Brett Handley:
[7/29] from: robert:muench:robertmuench at: 24-Jul-2003 11:56
> -----Original Message-----
> From: [rebol-bounce--rebol--com] [mailto:[rebol-bounce--rebol--com]]
<<quoted lines omitted: 4>>
> As background, the the main benefit of the Map function is
> collecting function results in a block.
Hi, just to throw in my 0.02, did you had a look at the C++ STL library?
Especially the concepts of iterators, algorithms, functonids, predicates
etc. seem to be very similar to what you are doing here. IIRC I brought
up the idea to use such "generic concepts" with Rebol long long ago. IMO
this would lead to a very cute generic Rebol library like the STL is for
C++. Robert
[8/29] from: brett:codeconscious at: 24-Jul-2003 21:26
Thanks Andrew, Gabriele, Volker and Robert for your responses.
Latest function below.
Andrew wrote:
> Note: compose/deep and: do [(block)]
Sorry Andrew I don't quite understand what you mean. But I have got rid
compose completely now :^)
Gabriele wrote:
> Small note: you should bind your RESULT word to a fresh context
Thanks for the alert. That prompted me to use USE, but then I realised I
would have a potential naming clash. Then I realised I don't need a result
variable or special context at all! Collect has gone very minimalistic :^)
Volker wrote:
> regarding filtering: there is 'remove-each
Thinking that it is faster to not insert than to insert then remove I
modified Collect to include a filter in the most efficient way I knew how.
Then I compared the timing of this function with just using Volker's
suggestion of removing later using Remove-each. The latter was faster. So I
ripped out my filter code again :^)
Robert wrote:
> did you had a look at the C++ STL library?
No, I haven't - I don't use C++. Sounds interesting though.
Collect is using a code generation approach - I wonder where it can lead.
collect: func [
{Collects block evaluations, use as body in For, Repeat, etc.}
block [block!] "Block to evaluate."
/init result "Initialise the result series."
/only "Inserts into result using Only refinement."
] [
result: any [result make block! 100]
reduce [
pick [insert insert/only] not only 'tail result 'do :block
result
]
]
Regards,
Brett.
[9/29] from: brett:codeconscious at: 24-Jul-2003 22:06
Don't you just hate it when after testing, trying some more and some more
testing you press Send and then test think "Oh no!". The last version worked
for Repeat but not for Foreach - and I still don't know why. This one seems
to work however.
>> repeat i 10 collect [i]
== [1 2 3 4 5 6 7 8 9 10]
>> for i 1 10 2 collect [i * 10]
== [10 30 50 70 90]
>> foreach [a b] [1 2 3 4] collect [a + b]
== [3 7]
>> foreach w [a b c d] collect [w]
== [a b c d]
collect: func [
{Collects block evaluations, use as body in For, Repeat, etc.}
block [block!] "Block to evaluate."
/init result "Initialise the result series."
/only "Inserts into result using Only refinement."
] [
result: any [result make block! 100]
reduce [
'head pick [insert insert/only] not only 'tail result to paren!
block
]
]
Regards,
Brett.
[10/29] from: rotenca:telvia:it at: 24-Jul-2003 14:52
Hi Brett,
> Don't you just hate it when after testing, trying some more and some more
> testing you press Send and then test think "Oh no!". The last version worked
> for Repeat but not for Foreach - and I still don't know why. This one seems
> to work however.
Foreach makes copy/deep on the body block to recurse well (repeat does not
make it)
> collect: func [
> {Collects block evaluations, use as body in For, Repeat, etc.}
<<quoted lines omitted: 8>>
> ]
> ]
this can also be:
reduce ['head pick [insert insert/only] not only 'tail result do block]
with a small change it can handle also paren! init value under last betas:
reduce ['head pick [insert insert/only] not only 'tail 'first reduce
[:result] do block]
---
Ciao
Romano
[11/29] from: greggirwin:mindspring at: 24-Jul-2003 8:35
Just to chime in (good thread BTW)...
RMM> Hi, just to throw in my 0.02, did you had a look at the C++ STL library?
RMM> Especially the concepts of iterators, algorithms, functonids, predicates
RMM> etc. seem to be very similar to what you are doing here. IIRC I brought
RMM> up the idea to use such "generic concepts" with Rebol long long ago. IMO
RMM> this would lead to a very cute generic Rebol library like the STL is for
RMM> C++. Robert
Smalltalk has similar concepts, and of course these types of things
are often taught in conjunction with Lisp, Scheme, and other
functional languages. Lots of places to draw inspiration from.
-- Gregg
[12/29] from: AJMartin:orcon at: 25-Jul-2003 4:27
Brett wrote:
> /init result "Initialise the result series."
I'd use this instead:
/initial result [series!] "Initialise the result series."
as it fits better with existing Rebol refinements. See 'array.
> But I have got rid compose completely now :^)
:)
I'm still using 'compose/deep, but that's because I want 'collect to work as
much like my 'map as I can get it.
Collect: function [
{Collects the results of block evaluations.}
Block [block!] "The block to 'do."
/Only "Inserts the result as a series."
/Full "Don't ignore none! values."
/Initial Results [series!]
] [
Result
] [
Results: any [Results copy []]
compose/deep [
if not any [
unset? set/any 'Result do [(Block)]
(pick [[none? :Result] []] not Full)
] [
(pick [insert insert/only] not Only) tail Results :Result
]
Results
]
]
>> foreach c "abcde" collect/Initial [to integer! c] ""
== "979899100101"
Andrew J Martin
ICQ: 26227169 http://www.rebol.it/Valley/ http://Valley.150m.com/
[13/29] from: andrew:martin:colenso:school at: 25-Jul-2003 8:34
Brett wrote:
> /init result "Initialise the result series."
Andrew wrote:
> /Initial Results [series! datatype!] "Specifies the type of
the result."
I'm using /Initial for my version of 'Collect, because it's like the
/Initial refinement in the 'Array function:
>> help array
USAGE:
ARRAY size /initial value
DESCRIPTION:
Makes and initializes a series of a given size.
ARRAY is a function value.
ARGUMENTS:
size -- Size or block of sizes for each dimension (Type: integer
block)
REFINEMENTS:
/initial -- Specify an initial value for all elements
value -- Initial value (Type: any)
And the 'datatype! specification allows me to be weird! :)
>> foreach c "abcde" collect/Initial [to integer! c] string!
== "979899100101"
>> foreach c "abcde" collect/Initial [to integer! c] block!
== [97 98 99 100 101]
>> foreach c "abcde" collect/Initial [to integer! c] hash!
== make hash! [97 98 99 100 101]
Collect: function [
{Collects the results of block evaluations.}
Block [block!] "The block to 'do."
/Only "Inserts the result as a series."
/Full "Don't ignore none! values."
/Initial Results [series! datatype!] "Specifies the type of the
result."
] [
Result
] [
Results: any [
all [
datatype? Results
make Results 0
]
Results
copy []
]
compose/deep [
if not any [
unset? set/any 'Result do [(Block)]
(pick [[none? :Result] []] not Full)
] [
(pick [insert insert/only] not Only) tail Results :Result
]
Results
]
]
Andrew J Martin
Attendance Officer &
Information Systems Trouble Shooter
Colenso High School
Arnold Street, Napier.
Tel: 64-6-8310180 ext 826
Fax: 64-6-8336759
http://colenso.net/scripts/Wiki.r?AJM
http://www.colenso.school.nz/
DISCLAIMER: Colenso High School and its Board of Trustees is not responsible (or legally
liable) for materials distributed to or acquired from user e-mail accounts. You can report
any
misuse of an e-mail account to our ICT Manager and the complaint will be investigated.
(Misuse can come in many forms, but can be viewed as any material sent/received that
indicate or suggest pornography, unethical or illegal solicitation, racism, sexism, inappropriate
language and/or other issues described in our Acceptable Use Policy.)
All outgoing messages are certified virus-free by McAfee GroupShield Exchange 5.10.285.0
Phone: +64 6 843 5095 or Fax: +64 6 833 6759 or E-mail: [postmaster--colenso--school--nz]
[14/29] from: brett:codeconscious at: 25-Jul-2003 14:39
---Andrew
> I'm using /Initial for my version of 'Collect, because it's like the
> /Initial refinement in the 'Array function:
Sounds good. I'll do the same.
> And the 'datatype! specification allows me to be weird! :)
I'd thought of preallocated series, but not the datatype spec. I'll copy
that! :^)
---Romano
> Foreach makes copy/deep on the body block to recurse well (repeat does not
> make it)
Ahah. Thank you.
> this can also be:
> reduce ['head pick [insert insert/only] not only 'tail result do
block]
> with a small change it can handle also paren! init value under last betas:
>
> reduce ['head pick [insert insert/only] not only 'tail 'first reduce
> [:result] do block]
The [do block], means that the block will be executed during reduce, which
is too early. I need it to execute only when the outside control function
evaluates it.
I don't understand the issue with the paren! init value. Could you give an
example how this version of my function will not work?
---latest examples
>> for i 1 10 2 collect [i * 10]
== [10 30 50 70 90]
>> foreach [a b] [1 2 3 4] collect [a + b]
== [3 7]
>> foreach w [a b c d] collect [w]
== [a b c d]
>> repeat e [a b c %.txt] collect/initial [e] %file
== %fileabc.txt
>> iota: func [n [integer!]][repeat i n collect/initial [i] make block! n]
>> iota 10
== [1 2 3 4 5 6 7 8 9 10]
---latest version
collect: func [
{Collects block evaluations, use as body in For, Repeat, etc.}
block [block!] "Block to evaluate."
/initial result [series! datatype!] "Initialise the result."
/only "Inserts into result using Only refinement."
] [
if not initial [result: block!]
result: any [all [datatype? result make result 1000] result]
reduce ['head pick [insert insert/only] not only 'tail result 'do
:block]
]
Regards,
Brett
[15/29] from: rotenca:telvia:it at: 25-Jul-2003 12:07
Hi Brett,
> I don't understand the issue with the paren! init value. Could you give an
> example how this version of my function will not work?
No, i have not such example (could it exists?), it was only to say that paren!
or do was the same for foreach.
paren! is usually faster than do block, so i should use paren!
The main difference is that to paren! make a copy of the block, so it uses
more memory, and if the user uses a reference to the block he can be fooled:
>> repeat i 10 collect-paren b: [if i > 5 [insert tail b [* 2]] i]
== [1 2 3 4 5 6 7 8 9 10]
>> repeat i 10 collect-do b: [if i > 5 [insert tail b [* 2]] i]
== [1 2 3 4 5 6 14 32 72 160]
But changing an executed block is not safe in general.
So i am not sure about the best solution. I vote for to paren! :-)
---
Ciao
Romano
[16/29] from: brett:codeconscious at: 26-Jul-2003 22:26
Romano wrote:
> paren! is usually faster than do block, so i should use paren!
>
> The main difference is that to paren! make a copy of the block, so it uses
> more memory, and if the user uses a reference to the block he can be
fooled:
...
> But changing an executed block is not safe in general.
> So i am not sure about the best solution. I vote for to paren! :-)
I tested the two versions do vs paren and the paren version for the code
that I was using was faster by about 20%, but maybe that was because I
didn't have much of it. I don't know if there is a best solution either
given the different handling in repeat and foreach. So pick what you want!
:^)
Regards,
Brett.
[17/29] from: robert:muench:robertmuench at: 28-Jul-2003 10:16
> -----Original Message-----
> From: [rebol-bounce--rebol--com] [mailto:[rebol-bounce--rebol--com]]
<<quoted lines omitted: 5>>
> things are often taught in conjunction with Lisp, Scheme, and
> other functional languages. Lots of places to draw inspiration from.
Hi, right. The STL is a quite different concept if you see it the first
time but the idea is very cute. I just want to give you some ramp-up to
it. The first thing the STL does, is separating algorithms from
data-structures. Next it defines a set of operators that can be used in
an abstract way:
sort(first, last, greater<T>());
Here, 'sort is the algorithm. 'first and 'last are pointers to the first
and last object of a datastructure. 'sort will iterate linear from
'first to 'last. The iteration to the next element is abstracted and the
implementation of the data-structure must know how to iterate from
'first to 'last. So 'sort just uses a function like 'next-element,
however this is implemented (in C++ this is done by pointer arithmetic).
The next thing is 'greater. This is the compare operator 'sort is going
to use. 'greater is type independent, you will specify the actual type
through 'T. The nice thing about the STL is, that there exists a bunch
of those functionids (IIRC that's what those things are called). So we
could even have used 'less<T> or whatever we define.
Further some info from some old FAQ:
What are containers?
Containers include such things as vectors, lists, queues,
priority queues, stacks, maps, and sets. In STL,
containers (data structures) are templatized. For
example, the stack class may be used with integers,
doubles, and user defined types.
What are iterators?
Iterators may be thought of as the key to STL, acting
as an intermediary between the algorithms and the
containers. You are already familiar with the concept
of an iterator when you think of the pointer used to
traverse an array. Iterators are objects in STL.
One may think of them as a finger moving across the
elements of a container. The five categories of
iterators are:
Random Access -> Bidirectional-> Forward -> Input
-> Output
How are iterators related to containers and algorithms?
One may think of each container and each algorithm as
being associated with a certain iterator. A vector has
a random access iterator, therefore it may use a random
access algorithms such as a sort. A container may use
any algorithm associated with its iterator or any
algorithm associated with an iterator to the right of
it in the above diagram. Therefore a vector (random
access iterator) may use algorithms associated with
bidirectional, forward, input or output iterators.
Can a vector be used with the binary_search algorithm
(takes a forward iterator) ? If we look at the diagram
above, forward is to the right of random access,
therefore we may use binary_search with a vector
container. Can a vector be used with copy (takes an
input and an output iterator)? Since input and output
are to the right of random access, vector may used
with copy.
There are quite a number of algorithms in STL,
including count(), copy(), replace( ), reverse( ), ...
Just as each container is associated with a certain
iterator, each algorithm is also associated with a
certain iterator(s).
count( ) - input iterator
copy ( ) - input and output iterator
replace( ) - forward iterator
reverse( ) - bidirectional iterator
Finally here are some links to get more about the idea (don't know if
all are still alive):
http://www.boost.org/
http://www.stlport.org/
http://www.sgi.com/Technology/STL/index.html
http://www.metabyte.com/~fbp/stl/effort.html
http://www.mindspring.com/~fluxsmith/Programming/library.html
http://www.sirius.com/~ouchida/
Robert
[18/29] from: g:santilli:tiscalinet:it at: 28-Jul-2003 10:32
Hi Robert,
On Monday, July 28, 2003, 10:16:38 AM, you wrote:
RMM> Hi, right. The STL is a quite different concept if you see it the first
RMM> time but the idea is very cute. I just want to give you some ramp-up to
RMM> it. The first thing the STL does, is separating algorithms from
RMM> data-structures. Next it defines a set of operators that can be used in
RMM> an abstract way:
Actually, this is all normal in Lisp etc. The STL is just a
complicated way to do it in a less powerful language such as C++.
;-)
If you think about it, it is this way in REBOL too. It's just that
we can't make custom datatypes.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[19/29] from: robert:muench:robertmuench at: 28-Jul-2003 16:08
> -----Original Message-----
> From: [rebol-bounce--rebol--com] [mailto:[rebol-bounce--rebol--com]]
<<quoted lines omitted: 5>>
> just a complicated way to do it in a less powerful language
> such as C++. ;-)
Hi, well I agree but we don't have a STL equivalent for Rebol yet. I,
for long, wish that I have a standard library that I can just use
plug-in in my projects. Yes, there is a lot of stuff available but not
consolidated and done in a conceptual straight way. Even in the
complicated C++ this works mostly perfect with STL.
> If you think about it, it is this way in REBOL too. It's just
> that we can't make custom datatypes.
Not only. Do we have all those STL algorithms done in a way, that
supports the generic approach of the STL? I don't think so. What I would
like to have is:
Foreach btree-datatype [...]
Foreach skip-list [...]
Etc.
And that foreach uses the most efficient way to iterate. Anyway, I think
Rebol has a good bunch of STL already build in. Lot of datatypes for
example. But we can do better in terms of generic library functions.
Robert
[20/29] from: g:santilli:tiscalinet:it at: 28-Jul-2003 16:21
Hi Robert,
On Monday, July 28, 2003, 4:08:43 PM, you wrote:
RMM> Foreach btree-datatype [...]
RMM> Foreach skip-list [...]
RMM> Etc.
We CAN do that across all series datatypes. We just don't have
custom datatypes yet.
Of course, we could work around it by providing a new set of
functions that work on any generic data structure (provided the
data structure tells the functions how to work on it), or by using
hacks like my custom-types.r. But I'd like to have the solution
instead of the work around. ;-)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[21/29] from: maximo:meteorstudios at: 28-Jul-2003 10:40
Hi,
> -----Original Message-----
> From: Robert M. Muench [mailto:[robert--muench--robertmuench--de]]
<<quoted lines omitted: 6>>
> Foreach btree-datatype [...]
> Foreach skip-list [...]
true, but its Really easy to overide most functions as an example, I've often rebuilt
the print to handle different datatypes differently. my current print, actualy prints
out object! as: "first obj", so instead of having a list which runs for 15 minutes (cause
it prints out all functions), it gives me a 2-3 line output.
I agree with gabrielle, though, that custom dataypes are high on my list of wanted features
too. And they would add greatly to the usefullness of the system.
the other thing I really would like to get are more hooks within the parser itself.
the ability to insert code just before a get and set call in python is genial. This
lets you create virtuall methods and attributes... for example in liquid right now, I
want to build an object to liquid mapper... well I just can't do it transparently because
the moment I do object/attribute: value, I overwrite the function that was set at the
place of the attribute, which is supposed to send a message to the liquid.
in python, I could have added a little hook before the set, which causes my code to actually
set the attribute, instead of the default code. that code would then call a liquid notification
of the pipe set to the attribute. Externally, the object still remains an object, but
internally, the object behaves quite differently.
just my 0.02
-MAx
[22/29] from: lmecir:mbox:vol:cz at: 26-Nov-2003 10:55
Hi Brett, Andrew, Romano et al.,
>---latest version
>collect: func [
<<quoted lines omitted: 8>>
>:block]
>]
I am sorry I missed your contribution on the subject somehow. I like it.
My two cents changing the behaviour of the function in cases like:
foreach head heads [...]
foreach insert inserts [...]
foreach tail tails [...]
foreach do does [...]
use [insert-only] [
insert-only: func [series value] [insert/only series value]
collect: func [
{Collects block evaluations, use as body in For, Repeat, etc.}
block [block!] "Block to evaluate."
/initial result [series!] "Initialise the result."
/only "Inserts into result using the Only refinement."
] [
result: any [make result result make block! 10]
reduce [
:head pick reduce [
:insert :insert-only
] not only :tail result :do block
]
]
]
-L
[23/29] from: AJMartin:orcon at: 24-Dec-2003 22:49
Hi, Ladislav.
Thanks for throwing in your two cents. Let's smunch my 'Collect with yours
and pick out the best survivor!
; Ladislav's:
use [insert-only] [
insert-only: func [series value] [insert/only series value]
collect: func [
{Collects block evaluations, use as body in For, Repeat, etc.}
block [block!] "Block to evaluate."
/initial result [series!] "Initialise the result."
/only "Inserts into result using the Only refinement."
] [
result: any [make result result make block! 10]
reduce [
:head pick reduce [
:insert :insert-only
] not only :tail result :do block
]
]
]
; Andrew's (just for Carl... :) ):
>> source collect
collect: func [
"Collects the results of block evaluations."
Block [block!] "The block to 'do."
/Only "Inserts the result as a series."
/Full "Don't ignore none! values."
/Initial Type [series! datatype!] "Specifies the type of the result."
][
use [Break Result Results] [
Break: func [
"Breaks out of the 'Collect."
/Return "Forces the loop function to return a Value."
Value [any-type!]
] [
system/words/break/return either Return [
Value
] [
Results
]
]
Results: any [
all [
datatype? Type
make Type 0
]
Type
copy []
]
compose/deep [
if not any [
unset? set/any 'Result do [(bind Block 'Break)]
(pick [[none? :Result] []] not Full)
] [
(pick [insert insert/only] not Only) tail Results :Result
Results
]
Results
]
]
]
Anyone else want to collide their code into the pile? :)
Andrew J Martin
Breeding the best Rebol code in this hemisphere!
ICQ: 26227169
http://www.rebol.it/Valley/
http://valley.orcon.net.nz/
http://Valley.150m.com/
[24/29] from: brett:codeconscious at: 26-Nov-2003 22:21
> >collect: func [
> > {Collects block evaluations, use as body in For, Repeat, etc.}
...
> I am sorry I missed your contribution on the subject somehow. I like it.
I like the way it underlines how the body of a looping function has an
independent existence. It amuses me to think of it as a just-in-time
expression factory.
> My two cents changing the behaviour of the function in cases like:
>
> foreach head heads [...]
> foreach insert inserts [...]
> foreach tail tails [...]
> foreach do does [...]
>
> use [insert-only] [
...
Thanks.
Regards,
Brett.
[25/29] from: lmecir:mbox:vol:cz at: 26-Nov-2003 20:10
Hi all,
two more cents to let Return work as usual:
use [insert-only] [
insert-only: func [series value] [insert/only series value]
collect: func [
{Collects block evaluations, use as body in For, Repeat, etc.}
[throw]
block [block!] "Block to evaluate."
/initial result [series!] "Initialise the result."
/only "Inserts into result using the Only refinement."
] [
result: any [make result result make block! 10]
reduce [
:head pick reduce [
:insert :insert-only
] not only :tail result :do block
]
]
]
[26/29] from: lmecir:mbox:vol:cz at: 26-Nov-2003 22:32
Forget about the last post, just an error.
-L
[27/29] from: rotenca:telvia:it at: 27-Nov-2003 0:19
Hi all,
two more cents to let Break work as usual: :-)
use [insert-only break-return] [
insert-only: func [series value] [insert/only series value]
break-return: func [value] [break/return value]
collectB: func [
{Collects block evaluations, use as body in For, Repeat, etc.}
block [block!] "Block to evaluate."
/initial result [series!] "Initialize the result."
/only "Inserts into result using the Only refinement."
][
result: reduce [:break-return any [make result result make block! 10]]
reduce [
:loop 1 reduce [
:change result :first reduce [:break-return]
:head pick reduce [:insert :insert-only] not only
:tail :second result :do block
:change result none
]
:do result
]
]
]
ex.
probe repeat x 10 collectb [if x = 6 [break] x * 2]
---
Ciao
Romano
[28/29] from: rotenca:telvia:it at: 27-Nov-2003 15:12
Hi, all
this works also with foreach (not only with loop and repeat):
use [insert-only break-return res] [
insert-only: func [series value] [insert/only series value]
break-return: func [value] [break/return value]
res: func [value] [func [] reduce [value]]
collectB: func [
{Collects block evaluations, use as body in For, Repeat, etc.}
block [block!] "Block to evaluate."
/initial result [series!] "Initialize the result."
/only "Inserts into result using the Only refinement."
][
initial: res reduce [none any [make result result make block! 10]]
reduce [
:loop 1 reduce [
:change :initial reduce [:break-return]
pick reduce [:insert :insert-only] not only
:tail :second :initial :do block
;:do block could be to-paren block, to make it a little more fast
; but so the block is copyed
:change :initial none
]
:do :initial
]
]
]
---
Ciao
Romano
[29/29] from: brett::codeconscious::com at: 29-Nov-2003 0:44
Interesting versions.
I first thought of collect when I was thinking about map. One downside of
map is that generally it requires a simple series as input, whereas looping
functions can have more flexibile iterations. Map also often needs to be
given a custom function which seems like overkill. The main thing that map
is useful for is the accumulation of the result. With collect I wanted just
the good bit of map. Unfortunately collect cannot always replace map.
When the series of items is empty, map returns an empty block, collect will
not provide a result (not even an empty block) because it doesn't get called
at all. The result in this case is whatever the looping function returns
when it doesn't do anything Eg.
repeat i 0 collect [i]
foreach x [] collect [x]
So some application code might be needed to handle that case - unless you
pass in a pre-existing series using /initial.
So I got the good bit with collect but with an unwelcome cost!
You win some, you lose some. :-/
Regards,
Brett.
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted