Maplist?
[1/13] from: joel:neely:fedex at: 9-Sep-2001 3:18
Hi, Ric, and all,
Ric Gagliardi wrote:
> Let me throw my variation in. I found I often used similar
> anonymous functions in map-like situations, so I made a
> variation that uses a block representing the body of the
> function instead:
>
> every: func [
...
> ]
> for example,
>
> >> every [a b] [1 2 3 4 5 6] [a + b]
> == [3 7 11]
>
Very nice!
> Similarly, I have 'keep:
>
> keep: func [
...
> ]
>
> >> keep a [1 2 3 4 5 6] [even? a]
> == [2 4 6]
>
Being of a more primitive mind-set, (and being somewhat partial
to FUNC, from my LISP days) I've often used something like:
>> map: function [[throw] f [any-function!] b [block!] /all] [
[ result item] [
[ result: make block! length? b
[ foreach val b [
[ item: f
val
[ if any [found? item all]
[
[ append/only result
item]]
[ result]
== [0 2 4]
>> map func [x] [x * x] [0 1 2 3 4 5]
== [0 1 4 9 16 25]
The point of the /ALL refinement becomes clearer when used
with another useful function:
>> ident: func [[throw] f [any-function!] x [any-type!]] [
[ if f x [x]
[ ]
>> ident :even? 3
== none
>> ident :odd? 3
== 3
so that IDENT gives back either the second argument or NONE,
depending on whether the second argument passes the filter
test given by the first argument.
Combining these two allows all sorts of on-the-fly filtering,
such as
>> map func [x] [ident :even? x] [0 1 2 3 4 5]
== [0 2 4]
or even (calculational-obscurity warning! ;-)
>> repeat rem [0 1 2 3 4] [
[ print [rem ":"
[ map
[ func [x] [ident func [x] [(x * x) // 5 = rem] x]
[ [0 1 2 3 4 5 6 7 8 9 10]
[ ]]
0 : 0 5 10
1 : 1 4 6 9
2 :
3 :
4 : 2 3 7 8
(For those not into number theory, this shows which natural
numbers have squares with various residues mod 5. Yawn...)
Seriously, the example is somewhat contrived, but was put
together to show the power of FUNC combined with higher-order
functions (as in Ladislav's very rich collection referenced
earlier in this thread).
-jn-
--
------------------------------------------------------------
Programming languages: compact, powerful, simple ...
Pick any two!
joel'dot'neely'at'fedex'dot'com
[2/13] from: allenk:powerup:au at: 9-Sep-2001 23:52
----- Original Message -----
From: "Joel Neely" <[joel--neely--fedex--com]>
To: <[rebol-list--rebol--com]>
Sent: Sunday, September 09, 2001 6:18 PM
Subject: [REBOL] Re: Maplist?
> Hi, Ric, and all,
> Ric Gagliardi wrote:
<<quoted lines omitted: 13>>
> >
> Very nice!
Is it intentional to set 'a and 'b in the global context too?
>> every [a b] [1 2 3 4 5 6] [a + b]
== [3 7 11]
>> a
== 5
>> b
== 6
Cheers,
Allen K
[3/13] from: ric:getorbital at: 10-Sep-2001 9:16
Thanks to both Allen and Joel for your pointers and counter examples. I
think I'll take some time to either spiff up my mapping functions or
exchange them altogether!
-- Ric
[4/13] from: dness:home at: 8-Sep-2001 16:54
I've look thru the documentation, but haven't had the answer to a very
simple question jump out at me yet.
Question:
What converts ["123" "45667"] to [123 45667]
or generalizing:
How do I generate the block that is the result of applying some
function to each element of an existing block (the classical
Lisp `Maplist') function;
perhaps more importantly,
what documentation should I look at that would point me in the
direction to solutions to this class of problems...
[5/13] from: tim:johnsons-web at: 8-Sep-2001 14:23
On Sat, Sep 08, 2001 at 04:54:46PM -0400, David Ness wrote:
> I've look thru the documentation, but haven't had the answer to a very
> simple question jump out at me yet.
>
> Question:
> What converts ["123" "45667"] to [123 45667]
That's one question: here's one way to do it:
ndx: 1
loop length? test[change at test ndx to-integer test/:ndx ndx: ndx + 1]
== 3 ; the loop returns the final value of ndx
>> test ; let's look at test
== [123 45667]
;NOTE: 'test was changed
> or generalizing:
> How do I generate the block that is the result of applying some
> function to each element of an existing block (the classical
> Lisp `Maplist') function;
This is a different case, if I understand your question. A second
block would be created, and one would want to test the type of each
member of the source block
; you might have something like this:
dst: make block! length? test ; save memory reallocation internally
ndx: 1
loop length? test[append dst to-integer test/:ndx ndx: ndx + 1]
>> test
== ["123" "4567"] ; is not changed
>> dst
== [123 4567] ; new block as a result
> perhaps more importantly,
> what documentation should I look at that would point me in the
> direction to solutions to this class of problems...
If I've understood you here, the core user's manual goes into series
if great depth with charts and everything.
PS: I wish I know more about lisp, I think a knowledge of lisp
would add to the rebol "literature".
Perhaps you're the one?
HTH
Tim
> --
> To unsubscribe from this list, please send an email to
> [rebol-request--rebol--com] with "unsubscribe" in the
> subject, without the quotes.
--
Tim Johnson <[tim--johnsons-web--com]>
http://www.johnsons-web.com
[6/13] from: dness:home at: 8-Sep-2001 17:52
Tim Johnson wrote:
> dst: make block! length? test ; save memory reallocation internally
> ndx: 1
<<quoted lines omitted: 3>>
> >> dst
> == [123 4567] ; new block as a result
Thanks. That's a help. I'll try it in my context.
I should say, though, that I am surprised give how _direct_ REBOL is
for solving so many problems that there isn't some sort of
APPLY function that would take a F and an [L} and produce a [F(L)]
IYSWIM.
> > perhaps more importantly,
> > what documentation should I look at that would point me in the
> > direction to solutions to this class of problems...
> If I've understood you here, the core user's manual goes into series
> if great depth with charts and everything.
Actually, since the `higher view' of what I want to do is so simple, I
thought it was undoubtedly _there_ somewhere in the documentation and I
had missed it. Your answer indicates that it isn't so simple, and
thus isn't `there' in the docs for good reason.
> PS: I wish I know more about lisp, I think a knowledge of lisp
> would add to the rebol "literature".
> Perhaps you're the one?
Certainly not yet, but perhaps someday when I am more comfortable
with REBOL.
Thanks again.
[7/13] from: larry:ecotope at: 8-Sep-2001 15:23
Hi David,
Here is a short and simple version of MAP. I agree it would be nice if RT
would implement a fast internal version of MAP. I find it extremely useful.
map: func [f1 b /local out][
out: copy []
repeat el b [append/only out f1 :el]
out
]
Use it like this for a named function (note the : prefix is needed to delay
full evaluation).
>> map :to-integer ["123" "45667"]
== [123 45667]
If the named function needs a refinement switch you delay evaluation with a
leading ' , like this:
>> map 'sine/radians [0 30 90]
== [0 -0.988031624092862 0.893996663600556]
You can also use it with an anonymous function (defined on the fly) like
this:
>> map func [x][x * x] [1 2 3]
== [1 4 9]
I am very interested in the list operators of Scheme, Lisp, and modern
functional languages like Haskell, Miranda, and Clean. I have implemented
many of them in REBOL. So feel free to ask more on this topic.
You might also benefit from Ladislav Mecir's highfun.r library:
http://www.sweb.cz/LMecir/highfun.r
Cheers
-Larry
[8/13] from: lmecir:mbox:vol:cz at: 9-Sep-2001 0:34
You can have a look at the http://www.sweb.cz/LMecir/highfun.r
[9/13] from: dness:home at: 8-Sep-2001 18:46
Ladislav Mecir wrote:
> You can have a look at the http://www.sweb.cz/LMecir/highfun.r
>
Thanks for the pointer. I think I've got my work cut out for me this
evening...
It looks _very_ interesting...
[10/13] from: dness:home at: 8-Sep-2001 18:48
Larry Palmiter wrote:
> Hi David,
> Here is a short and simple version of MAP. I agree it would be nice if RT
<<quoted lines omitted: 23>>
> Cheers
> -Larry
Thanks. Another nice piece of code to
(1) help me solve my problem;
(2) teach me some more REBOL
I appreciate your taking the trouble...
[11/13] from: al:bri:xtra at: 9-Sep-2001 10:54
You could try:
[
Rebol [
Name: 'Map
Title: "Map"
File: %"Map.r"
Home: http://zen.scripterz.org/Rebol/Enhancements/
Author: "Andrew Martin"
eMail: [Al--Bri--xtra--co--nz]
Date: 17/November/2000
Version: 1.5.0
History: [
1.5.0 {Removed 'throw-on-error to make it easier to track bugs down.}
1.4.0 {Modified to have any number of arguments per function}
1.3.0 {Modified to work with series! instead of block!.}
1.2.0 {unset! results are not returned - so allowing values to be filtered
out.}
1.1.0 "Added /Only refinement."
1.0.0 "Original."
]
Enhancement: 'Map
Acknowledgements: [
"Joel Neely"
"Ladislav"
]
Purpose: {Maps or applies the function to all elements of the series.}
Example: [
Map func [n [number!]] [n * n] [1 2 3]
;== [1 4 9]
Map [1 2 3] func [n [number!]] [n * n]
;== [1 4 9]
Map [1 2 3 4 5 6] func [a] [print [a]]
;1
;2
;3
;4
;5
;6
;== []
Map [1 2 3 4 5 6] func [a b] [print [a b]]
;1 2
;3 4
;5 6
;== []
Map [1 2 3 4 5 6] func [a b c] [print [a b c]]
;1 2 3
;4 5 6
;== []
]
]
Arguments: function [f [any-function!]] [Arguments] [
Arguments: make block! 2
foreach Argument pick :f 1 [
if refinement? :Argument [
break
]
append Arguments :Argument
]
Arguments
]
Map: function [
{Maps or applies the function to all elements of the series.}
Arg1 [any-function! series!]
Arg2 [any-function! series!]
/Only "Inserts the result of the function as a series."
][
Result Results Function Series
][
any [
all [
any-function? :Arg1 series? :Arg2
(Function: :Arg1 Series: :Arg2 true)
]
all [
any-function? :Arg2 series? :Arg1
(Function: :Arg2 Series: :Arg1 true)
]
throw make error! reduce [
'script 'cannot-use rejoin [
{"} mold 'Map " " mold type? :Arg1 {"}
]
rejoin [
{"} mold type? :Arg2 {"}
]
]
]
Results: make Series length? Series
do reduce [
'foreach Arguments :Function 'Series compose [
if not unset? set/any 'Result Function (Arguments :Function) [
either only [
insert/only tail Results :Result
][
insert tail Results :Result
]
]
]
]
Results
]
]
Andrew Martin
ICQ: 26227169 http://zen.scripterz.org
-><-
----- Original Message -----
From: "David Ness" <[DNess--Home--Com]>
To: "Rebol List" <[rebol-list--rebol--com]>
Sent: Sunday, September 09, 2001 8:54 AM
Subject: [REBOL] Maplist?
> I've look thru the documentation, but haven't had the answer to a very
> simple question jump out at me yet.
<<quoted lines omitted: 11>>
> [rebol-request--rebol--com] with "unsubscribe" in the
> subject, without the quotes.
-- Attached file included as plaintext by Listar --
-- File: Map.r
[
Rebol [
Name: 'Map
Title: "Map"
File: %"Map.r"
Home: http://zen.scripterz.org/Rebol/Enhancements/
Author: "Andrew Martin"
eMail: [Al--Bri--xtra--co--nz]
Date: 17/November/2000
Version: 1.5.0
History: [
1.5.0 {Removed 'throw-on-error to make it easier to track bugs down.}
1.4.0 {Modified to have any number of arguments per function}
1.3.0 {Modified to work with series! instead of block!.}
1.2.0 {unset! results are not returned - so allowing values to be filtered out.}
1.1.0 "Added /Only refinement."
1.0.0 "Original."
]
Enhancement: 'Map
Acknowledgements: [
"Joel Neely"
"Ladislav"
]
Purpose: {Maps or applies the function to all elements of the series.}
Example: [
Map func [n [number!]] [n * n] [1 2 3]
;== [1 4 9]
Map [1 2 3] func [n [number!]] [n * n]
;== [1 4 9]
Map [1 2 3 4 5 6] func [a] [print [a]]
;1
;2
;3
;4
;5
;6
;== []
Map [1 2 3 4 5 6] func [a b] [print [a b]]
;1 2
;3 4
;5 6
;== []
Map [1 2 3 4 5 6] func [a b c] [print [a b c]]
;1 2 3
;4 5 6
;== []
]
]
Arguments: function [f [any-function!]] [Arguments] [
Arguments: make block! 2
foreach Argument pick :f 1 [
if refinement? :Argument [
break
]
append Arguments :Argument
]
Arguments
]
Map: function [
{Maps or applies the function to all elements of the series.}
Arg1 [any-function! series!]
Arg2 [any-function! series!]
/Only "Inserts the result of the function as a series."
][
Result Results Function Series
][
any [
all [
any-function? :Arg1 series? :Arg2
(Function: :Arg1 Series: :Arg2 true)
]
all [
any-function? :Arg2 series? :Arg1
(Function: :Arg2 Series: :Arg1 true)
]
throw make error! reduce [
'script 'cannot-use rejoin [
{"} mold 'Map " " mold type? :Arg1 {"}
]
rejoin [
{"} mold type? :Arg2 {"}
]
]
]
Results: make Series length? Series
do reduce [
'foreach Arguments :Function 'Series compose [
if not unset? set/any 'Result Function (Arguments :Function) [
either only [
insert/only tail Results :Result
][
insert tail Results :Result
]
]
]
]
Results
]
]
[12/13] from: ric:getorbital at: 8-Sep-2001 17:37
Let me throw my variation in. I found I often used similar anonymous
functions in map-like situations, so I made a variation that uses a block
representing the body of the function instead:
every: func [
'param [word! block!]
list [series!]
body [block!]
/local result
][
result: copy []
either word? param [
forall list [
set param first list
append result do body
]
][
while [not tail? list][
foreach item param [
set :item first list
list: next list
]
append result do body
]
]
result
]
for example,
>> every [a b] [1 2 3 4 5 6] [a + b]
== [3 7 11]
Similarly, I have 'keep:
keep: func [
'param [word! block!]
list [series!]
body [block!]
/only filter [block!]
/local result
][
result: copy []
either word? param [
if only [make error! "Only works on param of type block!"]
forall list [
set param first list
if do body [append result get param]
]
][
while [not tail? list][
foreach item param [
set :item first list
list: next list
]
if do body [
foreach item param [
either only [
if find filter item [append result get item]
][
append result get item
]
]
]
]
]
result
]
>> keep a [1 2 3 4 5 6] [even? a]
== [2 4 6]
I use them all the time. BTW, any comments or critiques are welcome, as I
am still on the learning curve.
-- Ric
[13/13] from: carl:cybercraft at: 9-Sep-2001 13:07
On 09-Sep-01, David Ness wrote:
> I've look thru the documentation, but haven't had the answer to a
> very simple question jump out at me yet.
<<quoted lines omitted: 7>>
> what documentation should I look at that would point me in the
> direction to solutions to this class of problems...
I see others have replied with more functional functions while I was
working out the following rather limited one, but here it is
anyway...
convert: func [series [series!] apply [function! native! action!]][
head forall series [change series apply first series]
]
>> convert [1 2 3 "4" "5" "6"] :to-integer
== [1 2 3 4 5 6]
>> convert [1 2 3 "4" "5" "6"] :to-string
== ["1" "2" "3" "4" "5" "6"]
>> convert [1 2 3 a b c] :to-string
== ["1" "2" "3" "a" "b" "c"]
>> convert [1 2 3 a b c] :to-file
== [%1 %2 %3 %a %b %c]
>> convert ["123" "abc" "xyz"] :first
== [#"1" #"a" #"x"]
>> convert ["123" "abc" "xyz"] :reverse
== ["" "" ""]
>> convert convert ["123" "abc" "xyz"] :reverse :head
== ["321" "cba" "zyx"]
The limitations are that you can't use a function's refinements (as
with Larry's map function) or functions that require more than one
argument, so the likes of append will return an error.
--
Carl Read
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted