Hi Tomas,
as a general rule I would state:
Only functions which evaluate all of their arguments should be passed
to 'apply'. For other functions the result is undefined.
> : (de hi @ (println (rest)))
> -> hi
> : (de hello L (println L))
> -> hello
> : (hi 1 2 3)
> (1 2 3)
> -> (1 2 3)
> : (hello 1 2 3)
> (1 2 3)
> -> (1 2 3)
> : (apply hi (1 2) 3)
> (3 1 2)
> -> (3 1 2)
This is ok so far.
> : (apply hello (1 2) 3)
> NIL
> -> NIL
As 'hello' is not evaluating its arguments, it is not a good candidate
for 'apply'.
'apply' is a bit tricky internally. It actually behaves similar to the
normal interpreter. It looks at the function being passed, and prepares
the (evaluated) arguments in a suitable way:
- If the function is a Lisp function with a list of parameter
symbols, 'apply' binds the successive list elements to those
symbols.
- If the function is a Lisp function with an '@' parameter (variable
number of arguments), the environment is set up appropriately.
- If it is a Lisp function with a single symbolic parameter
(non-evaluating), that parameter is simply bound to NIL (as you
observed).
- If it is a function pointer (C-function), things get tricky. A data
structure (as shown in "doc/apply") is set up and maintained,
consisting of list cells and symbols (the lowest row), where the
successive list elements are inserted. Then the whole list is
passed to the internal function which then believes to have a list
of symbols as an argument, where it can happily "evaluate" each
symbol to retrieve the inserted value.
> : (and 1 2 3)
> -> 3
> : (apply and (1 2) 3)
> -> 2
Note, here too, that 'and' is not really suited for 'apply', as it does
not always evaluate all of its arguments. But, ok for now ...
> : (de and L
> (loop
> (NIL (setq @ (eval (car L) 1)))
> (NIL (pair (setq L (cdr L))) @) ) )
> # and redefined
> : (and 1 2 3)
> -> 3
This implementation of 'and' is not completely right. It does, for
example, not correctly handle the '@' symbol:
: (and (+ 3 4) (+ @ 1))
!? (+ @ 1)
b -- Number expected
If we look at the C implemenetation:
any doAnd(any x) {
any a;
x = cdr(x);
do {
if (isNil(a = EVAL(car(x))))
return Nil;
val(At) = a;
}
while (isCell(x = cdr(x)));
return a;
}
then we could do an analog Lisp function
(de and L
(use A
(loop
(NIL (setq A (eval (pop 'L) 1)))
(up @ A)
(NIL (pair L) A) ) ) )
This can be simplified a little, by taking advantage of '@':
(de and L
(loop
(NIL (eval (pop 'L) 1))
(up @ @)
(NIL (pair L) @) ) )
So this seems correct:
: (and (+ 3 4) (+ @ 1))
-> 8
'apply' of course does not work, for the reasons explained above.
> What is the fundamental difference between
>
> (de lfn L ...)
>
> and
>
> any cfn(any ex) {...}
Probably the fact that Lisp functions do not receive the full runtime
expression, but only the arguments.
The C-function 'and' recieves the list
(and (+ 3 4) (+ @ 1))
while the Lisp function only recieves
((+ 3 4) (+ @ 1))
Therefore, a Lisp function cannot access the function symbol (here
'and').
> Does it mean that there is a certain class of functions that can only be
> implemented in C and not in picolisp?
Hmm, I'm not sure. There might always be a way to get around this
limitation.
Cheers,
- Alex
--
UNSUBSCRIBE: mailto:[email protected]?subject=unsubscribe