[REBOL] Re: variable number of arguments
From: lmecir:mbox:vol:cz at: 27-Nov-2000 9:35
> GC> Can a function have a variable number of arguments?
>
> AM> No. But you can simulate it, by using 'any-type! function specifiers
and passing unset! as arguments. Better is to use refinements.
> LM> Yes, a function can have a variable number of arguments. Do is such a
function, as e.g. in:
> take-n: func [n /local spec] [
> spec: copy []
> for i 1 n 1 [
> append spec to word! append copy "a" to string! i
> ]
> func spec reduce [
> :reduce append reduce [
> to lit-word! append copy "take"to string! n
> ]
> spec
> ]
> ]
> LM> do take-n 4 1 2 3 4
> LM> == [take4 1 2 3 4]
>
> LM> , where Do took 5 arguments.
>
> AM> Actually, 'do took only one argument, the value returned from 'take-n
which had the argument "4"), which happened to be a function that is
evaluated by 'do that could take the next four arguments "1 2 3 4".
> LM> Think for the second time, please. Let's make sure, how many arguments
we have to take:
> make-sure1: func [
> {This function takes just one argument}
> f
> ][
> ; evaluate the argument
> f
> ]
> make-sure1 take-n 4 1 2 3 4
>
> The result:
> ** Script Error: f is missing its a1 argument
> ** Where: make-sure1
> ** Near: f
>
> make-sure2: func [
> {This function takes five arguments}
> f a2 a3 a4 a5
> ][
> ; evaluate f
> f a2 a3 a4 a5
> ]
>
> make-sure2 take-n 4 1 2 3 4
>
> The result:
> == [take4 1 2 3 4]
>
> LM>Conclusion: Do had to take five arguments to yield the correct result.
>
> AM>Actually, I disagree. 'Do only took one argument. The function returned
by 'take-n takes the four arguments. Rebol functions are a bit more active
than in conventional languages. Take for example, this function:
> fget: func [:a][probe :a]
> It doesn't do much, not even _evaluating_ it's 'a argument. Here's a
small session at Rebol console:
> >> fget: func [:a][probe :a]
> >> fget 1 + 2
> 1
> == 3
>
> Why did "1" get printed? And why was the result of 3 printed _after_ the
1
?
LM> I think, that the explanation of the above can be pretty simple:
function Fget asks for its argument to be fetched, which means, that no 1 +
2 calculation is allowed *before* supplying an argument to Fget. That is why
the evaluation of the addition is *postponed* here until Fget is evaluated.
Let's make sure:
make-sure3: func [:a] [2 * probe :a]
make-sure3 1 + 2
1
== 4
AM>
> Here's another function:
> feval: func [a][probe :a]
> Note that I've dropped one colon out in the "function spec". Therefore
'a is evaluated. Here's the Rebol console session:
> >> feval: func [a][probe :a]
> >> feval 1 + 2
> 3
> == 3
>
> Note that both cases, the line:
> probe :a
> never evaluates 'a. So where does 'a get evaluated? Effectively here:
> func [a]
> More exactly, 'a is evaluated inside the brackets after "func". Or
perhaps better to say that an evaluated argument in a function processes or
evaluates the input stream of values until a natural stopping point is
reached. In other words, the input stream reduces down to a value that is
not a func or prefix operator (effectively a function) and isn't a value
followed by a binary operator value. The input stream of values is also
terminated by the presence of a right square bracket. Because
continuations
, IIRC, aren't in Rebol, the function argument evaluation
mechanism can't "leap out" of the function body and resume processing the
upper
or "outer" level input stream of values.
LM> Here, as opposed to your previous example, the evaluation of the Feval's
argument is allowed *before* Feval gets it, that'a all. No "inside brackets"
evaluation is needed to explain the difference.
AM>
> So the error message:
>
> ** Script Error: f is missing its a1 argument
> ** Where: make-sure1
> ** Near: f
>
> means what it says, and 'do only has one argument.
>
> I hope that helps!
>
> Andrew Martin
> -><-
LM> It doesn't help, because you didn't succeed to explain, why you are'nt
able to write a Rebol function similar to Make-sure4:
make-sure4: func [
{This function takes five arguments}
f a2 a3 a4 a5
][
; evaluate f
f :a2 :a3 :a4 :a5
]
, but able to take any function (not only a function having at most four
arguments) and evaluate it correctly.
FYI my explanation is, that if such a hypothetical function had to evaluate
its first argument correctly, it should have supplied it all necessary
arguments, but that is not possible, because the only Rebol function capable
of doing that is currently the Do function.
This subject has something in common with Rebol orthogonality, where we see,
that Rebol, using itself a function capable of taking a variable number of
arguments, doesn't allow a user to define such a function routinely too. The
interesting thing about that is, that such functions can be added to Rebol
without *any* difficulty, because such functions basically do the same as
the functions taking a block as their only argument.
Thanks for the interesting discussion on the subject, I hope, that it wasn't
boring for anybody.
Regards
Ladislav