Hi All!

I've posted this before--never got much response--but I'll try again,
since I really want to pester Carl to add something like this to R3 if
others think it would be useful.

What is it?

     A function to collect values into a block, so you can avoid the
     local/copy/append/return dance in functions. e.g.
     
     fn: func [series /local res] [
         res: copy []
         foreach val series [append res val]
         res
     ]

     It was inspired by Brett Handley and Romano Paolo Tenca. I just
     came up with a different approach that worked better for me.
     
How does it work?

    It takes a word and a block as arguments. Anytime the word appears
    as a set-word! in the block, the value assigned to it is
    "collected".
    
    The above func would look like this:
    
    fn: func [series] [
        collect v [foreach val series [v: val]
    ]

Why bother?

    1) It reduces tedious code.

    2) It makes it clear that you're collecting values.

What are the downsides?

    It's a subtle dialect that overrides the meaning of set-words.
    (I've been using it for quite a while now, so I can't judge how
    unnatural it feels to others)
    
Where's the code?

    collect: func [
        [throw]
        {Collects block evaluations.}
        'word "Word to collect (as a set-word! in the block)"
        block [any-block!] "Block to evaluate"
        /into dest [series!] "Where to append results"
        /only "Insert series results as series"
        /local code marker at-marker? marker* mark replace-marker rules
    ] [
        block: copy/deep block
        dest: any [dest make block! []]
        ; "not only" forces the result to logic!, for use with PICK.
        ; insert+tail pays off here over append.
        ; FIRST BACK allows pass-thru assignment of value.
        code: compose [first back (pick [insert insert/only] not only) tail 
dest]
        marker: to set-word! word
        at-marker?: does [mark/1 = marker]
        ; We have to use change/part since we want to replace only one
        ; item (the marker), but our code is more than one item long.
        replace-marker: does [change/part mark code 1]
        marker*: [mark: set-word! (if at-marker? [replace-marker])]
        parse block rules: [any [marker* | into rules | skip]]
        do block
        head :dest
    ]

Got any examples?

        collect zz []
        collect zz [repeat i 10 [if (zz: i) >= 3 [break]]]
        collect zz [repeat i 10 [zz: i  if i >= 3 [break]]]
        collect zz [repeat i 10 [either i <= 3 [zz: i][break]]]
        dest: copy []
        collect/into zz [repeat n 10 [zz: n * 100]] dest
        collect zz [for i 1 10 2 [zz: i * 10]]
        collect zz [for x 1 10 1 [zz: x]]
        collect zz [foreach [a b] [1 2 3 4] [zz: a + b]]
        collect zz [foreach w [a b c d] [zz: w]]
        collect zz [repeat e [a b c %.txt] [zz: file? e]]
        iota: func [n [integer!]][collect zz [repeat i n [zz: i]]]
        iota 10
        collect zz [foreach x first system [zz: to-set-word x]]
        x: first system
        collect zz [forall x [zz: length? x]]
        x: first system
        collect zz [forskip x 2 [zz: length? x]]
        collect/only zz [foreach [a b] [1 2 3 4] [zz: a zz: b zz: reduce [a b a 
+ b]]]
        collect/only zz [
            foreach [a b] [1 2 3 4] [
                zz: a zz: b zz: reduce [a b a + b]
                foreach n reduce [a b a + b] [zz: n * 10]
            ]
        ]

        dest: copy ""
        collect/into zz [repeat n 10 [zz: n * 100 zz: " "]] dest

        dest: copy []
        collect/into zz [
            foreach [num blk] [1 [a b c] 2 [d e f] 3 [g h i]] [
                zz: num
                collect/only/into yy [
                    zz: blk
                    foreach word blk [zz: yy: num  yy: word]
                    yy: blk
                ] dest
            ]
        ] dest

Comments?

    This is where you come in.

    Is it something worth asking RT to include?

    How could it be improved?

    
-- Gregg                         

-- 
To unsubscribe from the list, just send an email to 
lists at rebol.com with unsubscribe as the subject.

Reply via email to