[EMAIL PROTECTED] wrote:
>
> Ladislav asked for some functional programming in REBOL, so I've
> come up with a challenge.
>
...
>
> 3. Return a block of the strings present in this structure:
> [[[3 "hello"] [6 "world"] [7 "from" "rebol" 21]]
> [[["hi"] ["this" ['aword] "is"] "a"] "test"]]
>
> (answer is ["hello" "world" "from" "rebol" "hi" "this"
> "is" "a" "test"])
>
> As it turns out, it isn't possible to do this in REBOL with
> purely functional code because there doesn't seem to be a way
> to prepend an element to a block in a non-destructive way.
I haven't seen any responses to challenge #3 (although my email
reading has been spotty, thanks to some turkey...) so the following
is my first posted stab at it. Critiques on performance and style
are welcome, as I am still working on which ideas in PROLOG, LISP,
etc. are viable in REBOL and which need to be re-thought.
NB: I consider these "functional" -- although local variables are
utilized -- because the locals are only initialized once and are
never REassigned. This is well-known shorthand (e.g. "let" from
LISP/SCHEME) where
foo: func [arg /local temp] [
temp: (... some expression1 on arg ...)
(... some expression2 on temp ...)
]
is just a syntactical (and likely a bit faster) variation of
baz: func [arg2] [
(... some expression2 on arg2 ...)
]
foo: func [arg1] [
baz (... some expression1 on arg1 ...)
]
because it uses local definition and expression evaluation instead of
(secondary) argument definition and function invocation to do the same
computation.
;
; transform a (not string!) series (block?, list?, ...) so that
; the first member is un-nested
;
pinch: func [arg /local front] [
either all [
series? arg
series? front: first arg
not any-string? front
][
pinch compose [(first front) (next front) (next arg)]
][
arg
]
]
>> pinch [[["hello" 0] "world" 1] [2 "!" 3]]
== ["hello" 0 "world" 1 [2 "!" 3]]
;
; flatten a (not string!) series? by concatenating the first
; element of the pinched argument with the flattened remainder
; of the pinched argument
;
; non-series arguments, string arguments, or empty arguments are
; their own flattened selves
;
flatten: func [arg /local loc] [
either all [
series? arg
not any-string? arg
not empty? arg
][
loc: pinch arg
compose [(first loc) (flatten next loc)]
][
arg
]
]
>> flatten [[["hello" 0] "world" 1] [2 "!" 3]]
== ["hello" 0 "world" 1 2 "!" 3]
;
; recursively create a result that consists of only the strings
; from the original argument
;
_onlystrings: func [arg] [
either empty? arg [
arg
][
either any-string? first arg [
compose [(first arg) (_onlystrings next arg)]
][
_onlystrings next arg
]
]
]
;
; produce the block of strings (per challenge #3) by finding the
; strings in the flattened structure
;
onlystrings: func [arg] [
_onlystrings flatten arg
]
>> onlystrings [[["hello" 0] "world" 1] [2 "!" 3]]
== ["hello" "world" "!"]
>> onlystrings [[[3 "hello"] [6 "world"] [7 "from" "rebol" 21]]
[ [[["hi"] ["this" ['aword] "is"] "a"] "test"]]
== ["hello" "world" "from" "rebol" "hi" "this" "is" "a" "test"]
Thus I think it IS possible to do challenge #3 in REBOL.
-jn-