REBOL3 tracker
  0.9.12 beta
Ticket #0000637 User: anonymous

Project:



rss
TypeWish Statuspending Date14-Feb-2009 17:24
Versionalpha 33 CategoryMezzanine Submitted byxuanin
PlatformAll Severityminor Prioritynormal

Summary ANY-OF, ALL-OF functions
Description These functions combine ANY and ALL with FOREACH, but return immediately when no further evaluation is needed:

ANY-OF: Evaluates a condition for each value(s) in a series and returns the first value(s) for which the condition is not FALSE or NONE.

ALL-OF: Evaluates a condition for each value(s) in a series and returns NONE at the first FALSE or NONE, or TRUE if all succeed.
Example code
>> any-of x [-1 4 10] [x > 0]
== 4

>> any-of [x y] [1 4 10 8 5 -3] [(x - 2) = y]
== [10 8]

>> all-of x [33 -1 24] [x > 0]
== none

>> all-of [x y] [1 2 3 4] [x < y]
== true

; Source of ANY-OF, using COMPOSE/deep and APPLY
any-of: func [
    "Returns the first value(s) for which the test is not FALSE or NONE."
    'word [word! block!] "Word or block of words to set each time (local)"
    data [series! any-object! map! none!] "The series to traverse"
    test [block!] "Condition to test each time"
][
    if data [
        foreach (word) data compose/deep [
            (:if) (to paren! test) [
                (:apply) (:quote) (:break) [(true) (
                    either word? word [to get-word! word] [
                        reduce [:reduce map-each w word [to get-word! w]]
                    ]
                )]
            ]
        ]
    ]
]

; Source of ALL-OF, using COMPOSE/deep and APPLY
all-of: func [
    "Returns TRUE if all value(s) pass the test, otherwise NONE."
    'word [word! block!] "Word or block of words to set each time (local)"
    data [series! any-object! map! none!] "The series to traverse"
    test [block!] "Condition to test each time"
][
    if data [
        foreach (word) data compose/deep [
            (:unless) (to paren! test) [
                (:apply) (:quote) (:break) [(true) (none)]
            ]
            (true)
        ]
    ]
]

; Source of ANY-OF, using nested REDUCE and COMPOSE, and creating a path
any-of: func [
    "Returns the first value(s) for which the test is not FALSE or NONE."
    'word [word! block!] "Word or block of words to set each time (local)"
    data [series! any-object! map! none!] "The series to traverse"
    test [block!] "Condition to test each time"
][
    if data [
        foreach (word) data reduce [
            :if to paren! test compose [
                (to path! reduce [:break 'return]) (
                    either word? word [to get-word! word] [
                        reduce [:reduce map-each w word [to get-word! w]]
                    ]
                )
            ]
        ]
    ]
]

; Source of ANY-OF, using nested REDUCEs, and creating a path
all-of: func [
    "Returns TRUE if all value(s) pass the test, otherwise NONE."
    'word [word! block!] "Word or block of words to set each time (local)"
    data [series! any-object! map! none!] "The series to traverse"
    test [block!] "Condition to test each time"
][
    if data [
        foreach (word) data reduce [
            :unless to paren! test reduce [
                to path! reduce [:break 'return] none
            ]
            true
        ]
    ]
]

Assigned ton/a Fixed in- Last Update5-Mar-2014 00:45


Comments
(0000907)
BrianH
5-Jun-2009 16:57

This would be a useful function. However, if you have the full *EACH word syntax and local words, they wouldn't be efficient enough to justify unless they are native, or work on large data sets.

I'll try out some possible mezzanine implementations, just in case.
(0002703)
BrianH
30-Oct-2010 21:13

It turns out that there is a reasonably efficient way to do this as a mezzanine after all, though the results look a lot like a Scheme macro.

Source of working implementations of these functions added to the example code section. These functions avoid capture of the names of the inner functions used by using literal references to those functions instead of using them by name. This is also why APPLY QUOTE is used to call BREAK/return.

As with all mezzanine loop functions, #539 applies. However, the fix to #1659 in alpha 108 makes this solution possible.
(0002720)
Carl
1-Nov-2010 02:25

That code looks way too much like scheme/lisp for my appetite. I'm not sure of your objective in hiding the internal words. Such code is difficult to source/reflect.

Before this is added to the mezzanine, it needs to be defined some other way.

Also, when everything in a COMPOSE is paren'd like that, it usually means that a REDUCE should have been used instead.
(0002721)
BrianH
1-Nov-2010 02:34

There's no other way that's as efficient, and that supports the full *EACH syntax. It's mildly ugly, but less so than the MAP-EACH function in R2. But it's the behavior that's important, and these behave perfectly. We can add them now and then dare the community to improve them :)

And the words won't be hidden from SOURCE or REFLECT, because the code that is generated is used and thrown away immediately. If you look at the source of ANY-OF or ALL-OF then you will see the get-words, same as in the source above.
(0002722)
Carl
1-Nov-2010 02:40

So, you're saying it's a limitation of *EACH?
(0002723)
BrianH
1-Nov-2010 03:28

*EACH syntax including the set-words is complex to replicate in mezzanine code. The only efficient way is through code generation, like what MAP-EACH in R2 does. For R3 we at least have the existing *EACH functions that implement the syntax already, so we don't have to manage that part. All we have to do is create a code block to pass to the existing FOREACH (in this case) that is safe for it to execute. And in the case of *EACH, safe to execute means not affected by captured words that are the same as those used to refer to inner functions. For instance, if the words passed to ALL-OF include the words 'unless, 'break or 'true, ALL-OF should still work properly. Using inline references to those functions instead solves the word capture problem.

Or we could bite the bullet as we have with the rest of the *EACH family and make ANY-OF and ALL-OF native. As long as the behavior matches what the above functions do (at least as apparent from the outside) then all will be good.

We could make MAP-EACH in R2 as simple as the above functions if we added the set-word syntax to R2's FOREACH, as has been requested. Right now it is much more complex than these.
(0002754)
BrianH
2-Nov-2010 08:00

Added versions of the source that use a nicer looking nested REDUCE and TO-PATH model. It wouldn't add much overhead (and even that should be constant rather than O(n)), and the code is less intimidating.

Note: I don't add them in comments here because pre is broken in CC comments.
(0004301)
BrianH
5-Mar-2014 00:45

Implemented in https://github.com/rebol/rebol/pull/201 - mezzanine, until we decide to be native later.

Date User Field Action Change
5-Mar-2014 00:45 BrianH Comment : 0004301 Added -
5-Mar-2014 00:45 BrianH Status Modified problem => pending
9-Nov-2010 20:58 BrianH Comment : 0002721 Modified -
2-Nov-2010 08:01 BrianH Comment : 0002754 Modified -
2-Nov-2010 08:01 BrianH Comment : 0002754 Modified -
2-Nov-2010 08:00 BrianH Comment : 0002754 Added -
2-Nov-2010 07:57 BrianH Code Modified -
1-Nov-2010 03:48 BrianH Comment : 0002723 Modified -
1-Nov-2010 03:45 BrianH Comment : 0002723 Modified -
1-Nov-2010 03:41 BrianH Comment : 0002723 Modified -
1-Nov-2010 03:37 BrianH Comment : 0002723 Modified -
1-Nov-2010 03:31 BrianH Comment : 0002723 Modified -
1-Nov-2010 03:28 BrianH Comment : 0002723 Modified -
1-Nov-2010 03:28 BrianH Comment : 0002723 Added -
1-Nov-2010 02:40 carl Comment : 0002722 Added -
1-Nov-2010 02:38 carl Comment : 0002720 Modified -
1-Nov-2010 02:36 BrianH Comment : 0002721 Modified -
1-Nov-2010 02:34 BrianH Comment : 0002721 Added -
1-Nov-2010 02:33 carl Comment : 0002720 Modified -
1-Nov-2010 02:29 carl Comment : 0002720 Modified -
1-Nov-2010 02:28 carl Comment : 0002720 Modified -
1-Nov-2010 02:25 carl Comment : 0002720 Added -
1-Nov-2010 02:18 carl Status Modified reviewed => problem
30-Oct-2010 22:23 BrianH Description Modified -
30-Oct-2010 21:34 BrianH Code Modified -
30-Oct-2010 21:24 BrianH Code Modified -
30-Oct-2010 21:23 BrianH Comment : 0002703 Modified -
30-Oct-2010 21:17 BrianH Code Modified -
30-Oct-2010 21:13 BrianH Comment : 0002703 Added -
30-Oct-2010 21:05 BrianH Code Modified -
30-Oct-2010 21:05 BrianH Category Modified Unspecified => Mezzanine
30-Oct-2010 19:51 BrianH Category Modified => Unspecified
30-Oct-2010 19:51 BrianH Description Modified -
5-Jun-2009 16:57 BrianH Comment : 0000907 Added -
5-Jun-2009 16:31 BrianH Code Modified -
5-Jun-2009 16:29 BrianH Priority Modified low => normal
15-Feb-2009 04:38 BrianH Status Modified submitted => reviewed
15-Feb-2009 04:38 BrianH Code Modified -
14-Feb-2009 17:45 xuanin Code Modified -
14-Feb-2009 17:45 xuanin Description Modified -
14-Feb-2009 17:24 xuanin Ticket Added -