[REBOL] Re: variable number of arguments
From: al:bri:xtra at: 28-Nov-2000 21:29
> > >> 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
While that argument seems to fit, it doesn't fit the fact that there's no
do
involved? Functions don't need to ask "do" to evaluate themselves, they
actively get their own arguments, when they're evaluated.
> 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.
No, the function just evaluates it's own arguments as specfied by it's
function spec. There's no need for the function to ask an external
evaluation system to do it.
> 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!
> LM> It doesn't help, because you didn't succeed to explain, why you aren't
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.
You can if you delay evaluation until the function is in the same context as
it's arguments:
>> do func [a b c][print [a + 10 b + 20 c + 30]] 1 2 3
11 22 33
which is effectively what your function 'take-n simplifies down to.
> 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.
'do doesn't do that. It only seems to.
> 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.
Here's how 'do works for the example above. Rebol evaluates 'do. 'do
requires one arguement and evaluates it's one argument, the 'func word
(which happens to be next at the "instruction pointer"). 'func evaluates
it's two arguments, the spec and body blocks, and returns itself as a
function! datatype. (The input "instruction pointer" is now at the start of
the "1 2 3" sequence. 'do sees the function! datatype and evaluates the
function! datatype again. The function checks out its spec "[a b c]" and
evaluates the "1 2 3" in succession (advancing the "instruction pointer"
successively) and assigns the values to "a b c" then evaluates it's function
body (print "11 22 33"), returning the last result in the block to 'do,
which is unset!, which the console won't display.
> Thanks for the interesting discussion on the subject, I hope, that it
wasn't boring for anybody.
It's been interesting. I had to really think about it. Reminded me of
programming in Intel 8085 machine code and Motorola 6809 assembler, but this
was a lot easier.
Andrew Martin
Rebol assembler!
ICQ: 26227169 http://members.nbci.com/AndrewMartin/