Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

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