[REBOL] Who is that grouch? -or- Fun with functions! Re:(6)
From: joel:neely:fedex at: 5-Oct-2000 16:02
Hi, Andrew,
I love peer review! Open source works!
[Al--Bri--xtra--co--nz] wrote:
> > nondiv: func [d] [func [n] [either n // d = 0 [none] [n]]]
>
> This could be quicker as:
> nondiv: func [d] [func [n] [if n // d <> 0 [n]]]
> as 'if returns 'none when the condition is false.
>
> Also, this:
> > map: function [[catch] b [block!] f [function!] /all]
> is better as:
>
> map: function [[catch] b [block!] f [any-function!] /all]
>
> so you can use native! functions as well.
>
I've changed my copy to reflect these suggestions. Thanks! (I *did*
say it was the "latest" version, not the "last" version...)
> jn, is there a name for a generic function like:
>
> >> something: function [B [block!] F [any-function!]] [Arg1] [
> [ Arg1: first B
> [ B: next B
> [ foreach Arg2 B [
> [ Arg1: F Arg1 Arg2
> [ ]
> [ Arg1
> [ ]
> >>
> >> something [1 2 3 4 5] :+
> == 15
>
Well, APL called it "reduce", but that name is already taken! ;-)
The next most common name I can recall for that kind of thing is
accumulate
, but I'm too lazy to type that all the way out.
I suggest one slight change: supplying the initial value of the
accumulator lets it function correctly even with an empty block
of values. Normally one would use a left identity appropriate for
the f in use (e.g., 0 for addition, 1 for multiplication, etc.).
With this change in hand, we get:
accumulate: func [a [any-type!] b [block!] f [any-function!]] [
foreach c b [a: f a c]
a
]
which allows us to say
>> accumulate 0 iota 20 :+
== 210
or
>> accumulate 1 iota 10 :*
== 3628800
Since the accumulation function need not be symmetric, we can also say
>> accumulate "" iota 10 :append
== "12345678910"
Of course, some functions don't have a left identity (theoretically or
practically), so it's up to the user to choose a reasonable stand-in:
>> accumulate 9999999 iota 20 :min
== 1
>> accumulate -9999999 iota 20 :max
== 20
Incidentally, there's a whole family of such so-called higher-order
functions that can be quite interesting. The next one (I can't recall
if there's a common name for it) can be used for statistics and other
fun things:
pair-wise: function [
b1 [block!] b2 [block!] f [any-function!]
][
r
][
r: make block! min length? b1 length? b2
loop min length? b1 length? b2 [
append r f first b1 first b2
b1: next b1
b2: next b2
]
r
]
...such as...
>> my-scores: [4 7 16 2 12 13]
== [4 7 16 2 12 13]
>> your-scores: [9 5 15 1 15 15]
== [9 5 15 1 15 15]
>> winning-scores: pair-wise my-scores your-scores :max
== [9 7 16 2 15 15]
>> losing-scores: pair-wise my-scores your-scores :min
== [4 5 15 1 12 13]
>> spreads: pair-wise winning-scores losing-scores :subtract
== [5 2 1 1 3 2]
Then (hold on to your Funk-and-Wagnall's) a function named after the
mathematical operation known as "convolution" can be defined as
convolve: func [
a [any-type!]
b1 [block!] b2 [block!]
fa [any-function!] fb [any-function!]
][
accumulate a pair-wise b1 b2 :fb :fa
]
...which can do tricks such as...
>> worst-winning-score: convolve 9999 my-scores your-scores :min :max
== 2
>> best-losing-score: convolve -9999 my-scores your-scores :max :min
== 15
>> season-grand-score: convolve 0 my-scores your-scores :+ :max
== 64
...as well as the more mathematical...
>> inner-product: convolve 0 my-scores your-scores :+ :*
== 688
> And if you're Grouchy, who's Sneezy, Happy, Doc,... ? :-)
>
Well, after all the interesting and useful suggestions from the list,
I guess I'm Happy! (Although overlooking the quadratic time complexity
of my earlier versions of iota and map made me feel Dopey!)
-jn-
--
; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677
REBOL [] print to-string debase decompress #{
789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC
B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}