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:picol...@software-lab.de?subject=unsubscribe

Reply via email to