From: Jonathon McKitrick
Subject: When to use apply
Date: 
Message-ID: <1137782072.937735.290510@g44g2000cwa.googlegroups.com>
I can understand when a variable is bound to a function you might want
to do this:

(setf foo #'bar)
(apply foo arg1 arg2)


but what is the point to do this, which I have seen in code...

(apply #'bar arg1 arg2)

What does this gain?

From: ··············@hotmail.com
Subject: Re: When to use apply
Date: 
Message-ID: <1137782597.099279.47090@g43g2000cwa.googlegroups.com>
Jonathon McKitrick wrote:
> I can understand when a variable is bound to a function you might want
> to do this:
>
> (setf foo #'bar)
> (apply foo arg1 arg2)
>
>
> but what is the point to do this, which I have seen in code...
>
> (apply #'bar arg1 arg2)
>
> What does this gain?

Look carefully at the specification for apply. In particular,  the
final argument can be a list, allowing the fixed-arity apply call to
pass an arbitrarily-long list of arguments it acquired through arg2.

In combination with the &rest feature of lambda lists, functions can
pass on an arbitrarily long set of keyword arguments, for instance,
without having to explicitly parse all of those keyword options before
passing them down the call chain.
From: Pascal Bourguignon
Subject: Re: When to use apply
Date: 
Message-ID: <874q3yiqwt.fsf@thalassa.informatimago.com>
···············@hotmail.com" <············@gmail.com> writes:

> Jonathon McKitrick wrote:
>> I can understand when a variable is bound to a function you might want
>> to do this:
>>
>> (setf foo #'bar)
>> (apply foo arg1 arg2)
>>
>>
>> but what is the point to do this, which I have seen in code...
>>
>> (apply #'bar arg1 arg2)
>>
>> What does this gain?
>
> Look carefully at the specification for apply. In particular,  the
> final argument can be a list, allowing the fixed-arity apply call to
                 MUST
> pass an arbitrarily-long list of arguments it acquired through arg2.
>
> In combination with the &rest feature of lambda lists, functions can
> pass on an arbitrarily long set of keyword arguments, for instance,
             Up to the CALL-ARGUMENTS-LIMIT, which can be as low as 50.
> without having to explicitly parse all of those keyword options before
> passing them down the call chain.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

What is this talk of 'release'? Klingons do not make software 'releases'.
Our software 'escapes' leaving a bloody trail of designers and quality
assurance people in it's wake.
From: Jonathon McKitrick
Subject: Found a place my code needs apply
Date: 
Message-ID: <1138155866.521406.17770@g43g2000cwa.googlegroups.com>
Thanks to all for their replies.

I have a place in my code where I have 2 lists, and I need to calculate
the total of the differences between corresponding terms.  So:
list a = (a, b, c, d)
list z = (w, x, y, z)

I need the sum of (a-w, b-x, c-y, d-z)... actually the absolute values
of those terms.

After performing this for one list a and several list z and saving the
results in a separate list, I have to determine which list has the
smallest delta difference.  To find the smallest one, I use:

(position (apply #'min total-deltas) (reverse total-deltas))

Since each delta was pushed on, I had to reverse them.

But apply works great here.
From: André Thieme
Subject: Re: Found a place my code needs apply
Date: 
Message-ID: <1138156999.670538.84380@g43g2000cwa.googlegroups.com>
Jonathon McKitrick schrieb:

> Thanks to all for their replies.
>
> I have a place in my code where I have 2 lists, and I need to calculate
> the total of the differences between corresponding terms.  So:
> list a = (a, b, c, d)
> list z = (w, x, y, z)
>
> I need the sum of (a-w, b-x, c-y, d-z)... actually the absolute values
> of those terms.

And a, b, c, d, w, x, y, z are numbers?
(mapcar #'(lambda (a b) (abs (- a b))) '(10 20 3 4) '(1 2 30 40)) => (9
18 27 36)


> After performing this for one list a and several list z and saving the
> results in a separate list, I have to determine which list has the
> smallest delta difference.  To find the smallest one, I use:
>
> (position (apply #'min total-deltas) (reverse total-deltas))

Hmm, I don't understand this use of apply in this case. I mean, I don't
understand what you win by using it over: (position (min total-deltas)
(reverse total-deltas))
Doesn't that work?


> Since each delta was pushed on, I had to reverse them.

If you constructed total-deltas freshly you could use (nreverse
total-deltas).
By solving your problem with functional programming there might be the
chance to do this calculation without pushing the deltas manually into
a list.


André
--
From: Jonathon McKitrick
Subject: Re: Found a place my code needs apply
Date: 
Message-ID: <1138164255.342828.189070@g47g2000cwa.googlegroups.com>
Here's actually what I did... maybe I didn't provide enough details
before....

(defun fit-a-profile (comp1 comp2)
  #+rpt-debug (format t "Compare:~%~A~%~A~%" comp1 comp2)
  (let (deltas)
    (setf deltas (map 'vector #'(lambda (a b) (abs (- a b))) comp1
comp2))
    #+rpt-debug (format t "Deltas: ~A~%" deltas)
    (let ((total-delta ))
      (setf total-delta (reduce #'+ deltas))
      #+rpt-debug (format t "Total delta: ~A~%" total-delta)
      total-delta)))

(defmethod fit-profiles ((rpt <report>))
  (let (total-deltas)
    #+rpt-debug (format t "Total deltas to start: ~A~%" total-deltas)
    (dotimes (profile 5)
      (query-profile-by-number (format nil "~A" (1+ profile)))
      (push (fit-a-profile (components rpt) (query-profile-components))
total-deltas)
      #+rpt-debug (format t "Total deltas so far: ~A~%" total-deltas))
    #+rpt-debug (format t "Reversed deltas: ~A~%" (reverse
total-deltas))
    (1+ (position (apply #'min total-deltas) (reverse total-deltas)))))
From: Coby Beck
Subject: Re: Found a place my code needs apply
Date: 
Message-ID: <sXEBf.95825$m05.61287@clgrps12>
"Andr� Thieme" <······························@justmail.de> wrote in message 
····························@g43g2000cwa.googlegroups.com...
Jonathon McKitrick schrieb:

?> After performing this for one list a and several list z and saving the
>> results in a separate list, I have to determine which list has the
>> smallest delta difference.  To find the smallest one, I use:
>>
>> (position (apply #'min total-deltas) (reverse total-deltas))
>
>Hmm, I don't understand this use of apply in this case. I mean, I don't
>understand what you win by using it over: (position (min total-deltas)
>(reverse total-deltas))
>Doesn't that work?

Look again!  MIN doesn't take a list argument.

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: André Thieme
Subject: Re: Found a place my code needs apply
Date: 
Message-ID: <1138192972.590316.233870@o13g2000cwo.googlegroups.com>
Coby Beck schrieb:

> "André Thieme" <······························@justmail.de> wrote in message
> ····························@g43g2000cwa.googlegroups.com...
> Jonathon McKitrick schrieb:
>
> ?> After performing this for one list a and several list z and saving the
> >> results in a separate list, I have to determine which list has the
> >> smallest delta difference.  To find the smallest one, I use:
> >>
> >> (position (apply #'min total-deltas) (reverse total-deltas))
> >
> >Hmm, I don't understand this use of apply in this case. I mean, I don't
> >understand what you win by using it over: (position (min total-deltas)
> >(reverse total-deltas))
> >Doesn't that work?
>
> Look again!  MIN doesn't take a list argument.

You and Jonathan are right, thanks.


André
--
From: Pascal Bourguignon
Subject: Re: Found a place my code needs apply
Date: 
Message-ID: <87u0bs1z46.fsf@thalassa.informatimago.com>
"Jonathon McKitrick" <···········@bigfoot.com> writes:

> Thanks to all for their replies.
>
> I have a place in my code where I have 2 lists, and I need to calculate
> the total of the differences between corresponding terms.  So:
> list a = (a, b, c, d)
> list z = (w, x, y, z)
>
> I need the sum of (a-w, b-x, c-y, d-z)... actually the absolute values
> of those terms.
>
> After performing this for one list a and several list z and saving the
> results in a separate list, I have to determine which list has the
> smallest delta difference.  To find the smallest one, I use:
>
> (position (apply #'min total-deltas) (reverse total-deltas))
>
> Since each delta was pushed on, I had to reverse them.

You can use nreverse, since total-deltas is a newly consed list.

You need to reverse only in the case you want the first list when two
have the same total delta.  If you don't mind getting one or the
other, then you can just do a substraction:

(- (length total-delta) 1
   (position (apply #'min total-deltas) total-deltas))


Also, even if you mind getting the one, you could use :from-end t

(- (length total-delta) 1
   (position (apply #'min total-deltas) total-deltas :from-end t))


> But apply works great here.

That is, until: (<= call-argument-limit (length a))

(- (length total-delta) 1
   (position (reduce #'min total-deltas) total-deltas :from-end t))


I write (length total-delta), but you will probably have this value
around already, since it's the number of your other lists.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Specifications are for the weak and timid!"
From: Kaz Kylheku
Subject: Re: When to use apply
Date: 
Message-ID: <1137784286.913996.165780@g49g2000cwa.googlegroups.com>
Jonathon McKitrick wrote:
> I can understand when a variable is bound to a function you might want
> to do this:
>
> (setf foo #'bar)
> (apply foo arg1 arg2)

In Common Lisp, the direct way of calling a function, namely specifying
it in the first position of a compound expression, only allows function
names: symbols, lambda expressions or special expressions like (setf
...):

  (print 'foo)
  ((lambda (x y) (+ x y) 3 4)
  ((setf x-coordinate) point 3.0)

So if you have a function value, you /have/ to use some applicator to
call it. It's not something you "might want". If the function is to be
called, an applicator must be used
 FUNCALL, APPLY, MAPCAR and so forth. There are many to choose from.

> but what is the point to do this, which I have seen in code...
>
> (apply #'bar arg1 arg2)
>
> What does this gain?

The direct way of calling a function only provides you one "flavor" of
doing it. The function name is followed by some argument expressions
which are evaluated. Each expression produces a single argument value.

This way of calling a function is equivalent to FUNCALL. That is to
say:

  (F A1 A2 ... AN)

is the same as:

 (FUNCALL #'F A1 A2 ... AN)

Thus if someone wrote (funcall #'bar arg1 arg2), it would be right to
ask: why? You are using the direct function name. The function does not
come from an object or a variable binding, so why indirect on it?

However, the applicators other than FUNCALL provide semantic variation
that is useful on its own, even when you are dealing with a direct
function.

APPLY has a very useful feature that is not found in direct function
calling or in FUNCALL. Namely, the last argument to APPLY must evaluate
to a list object. That list object is cracked open by APPLY, and each
of its elements become additional arguments to the function.

APPLY is very useful in writing wrappers for variable-argument
functions, because it provides a way to pass down the &rest arguments:

  (defun wrap-func (&rest args)
    (apply #''func args))

You can call WRAP-FUNC with any number of arguments, and it just
bounces them down to FUNC. You could not do that with FUNCALL, because
(FUNCALL #'FUNC ARGS) would call the function with one argument which
is a list.

Without APPLY, you would have to resort to constructing the source code
of a function call, and the passing it to the evaluator (EVAL), a
grossly inefficient hack:

  (eval (cons 'func args))

Orl, equivalently, using backquote syntax withs splicing:

  (eval `(func ,@args))

The above EVAL idiom sometimes appears in newbie code, when they
haven't learned about APPLY yet.

And of course, the other applicators like MAPCAR all have their unique,
special semantic properties.

You wouldn't ask what's the point of writing (MAPCAR #'BAR ARG1 ARG2),
right?
From: tichy
Subject: Re: When to use apply
Date: 
Message-ID: <dqrpkg$mbh$1@atlantis.news.tpi.pl>
Kaz Kylheku wrote:

snip...

>   ((setf x-coordinate) point 3.0)

...

Hi. I think one should use (funcall #'(setf ...) ...),
or I missed something ?

Regards, Szymon.
From: Brian Downing
Subject: Re: When to use apply
Date: 
Message-ID: <uJ7Bf.509531$084.131488@attbi_s22>
In article <············@atlantis.news.tpi.pl>,
tichy  <···········@o2.pl> wrote:
> Kaz Kylheku wrote:
> >   ((setf x-coordinate) point 3.0)
> 
> Hi. I think one should use (funcall #'(setf ...) ...),
> or I missed something ?

No, you're right.  I think some implementations (CLISP?) let you write
((setf foo) bar baz), but the specification says:

> If the car of the compound form is not a symbol, then that car must be a
> lambda expression, in which case the compound form is a lambda form.
 - http://www.lispworks.com/documentation/HyperSpec/Body/03_abab.htm:

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: jayessay
Subject: Re: When to use apply
Date: 
Message-ID: <m3oe26btrr.fsf@rigel.goldenthreadtech.com>
"Jonathon McKitrick" <···········@bigfoot.com> writes:

> I can understand when a variable is bound to a function you might want
> to do this:
> 
> (setf foo #'bar)
> (apply foo arg1 arg2)
> 
> 
> but what is the point to do this, which I have seen in code...
> 
> (apply #'bar arg1 arg2)
> 
> What does this gain?

Let bar be a function of arbitrary number of arguments:

(defun bar (&rest args) ...)

Actually, the way you have it, it is more likely (though not
necessarily) to have this signature:

(defun bar (arg1 &rest args) ...)

Your arg2 argument is a list[1] containing the variable number of
"remaining" arguments to bar.  arg2 is computed at runtime.  So,

(apply #'bar arg1 arg2) supports calling bar with argument sets
computed at runtime.


/Jon


1. (must be actually, see http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#spreadable_argument_list_designator)

-- 
'j' - a n t h o n y at romeo/charley/november com
From: André Thieme
Subject: Re: When to use apply
Date: 
Message-ID: <1137892856.992667.223010@z14g2000cwz.googlegroups.com>
Jonathon McKitrick schrieb:

> I can understand when a variable is bound to a function you might want to do this:
>
> (setf foo #'bar)
> (apply foo arg1 arg2)
>
>
> but what is the point to do this, which I have seen in code...
>
> (apply #'bar arg1 arg2)
>
> What does this gain?

Try to write a function nth-elements which takes a number n and any
number of lists and returns a list of the nth's element of each list.

(nth-elements 3 '(10 20 hello x world) '(-1 -2 -3 y) '(z0 z1 z2 z))  =>
 (x y z)

Please make it a recursive function (without a loops, etc.).
When it is a recursive function you will come to the point where
nth-elements will call itself. This will be the moment it will become
hairy for you. When you reached this point: try it without apply for a
few minutes. If you can't continue: use apply.
Here is the first line:
(defun nth-elements (n &rest lists)


André
--
From: Michael Price
Subject: Re: When to use apply
Date: 
Message-ID: <slrndt6afu.3qq.malus42@yahoo.com>
On 2006-01-22, Andr� Thieme <······························@justmail.de> wrote:
>  Jonathon McKitrick schrieb:
> > but what is the point to do this, which I have seen in code...
> >
> > (apply #'bar arg1 arg2)
> >
> > What does this gain?
> 
>  Try to write a function nth-elements which takes a number n and any
>  number of lists and returns a list of the nth's element of each list.
> 
>  (nth-elements 3 '(10 20 hello x world) '(-1 -2 -3 y) '(z0 z1 z2 z))  =>
>   (x y z)
> 
>  Please make it a recursive function (without a loops, etc.).
>  When it is a recursive function you will come to the point where
>  nth-elements will call itself. This will be the moment it will become
>  hairy for you. When you reached this point: try it without apply for a
>  few minutes. If you can't continue: use apply.

That is a neat exercise to illustrate the usefulness of apply.

Of course, after going through all of that you then see why loop is so
handy:

CL-USER> (defun nth-elements (n &rest lists)
           (loop for item in lists collect (nth n item)))

NTH-ELEMENTS
CL-USER> (nth-elements 3 '(10 20 hello x world) '(-1 -2 -3 y) '(z0 z1 z2 z))

(X Y Z)

Michael
From: funkyj
Subject: Re: When to use apply
Date: 
Message-ID: <1138124595.003359.259490@g44g2000cwa.googlegroups.com>
André Thieme wrote:

> Try to write a function nth-elements which takes a number n and any
> number of lists and returns a list of the nth's element of each list.
>
> (nth-elements 3 '(10 20 hello x world) '(-1 -2 -3 y) '(z0 z1 z2 z))  =>
>  (x y z)
>
> Please make it a recursive function (without a loops, etc.).
> When it is a recursive function you will come to the point where
> nth-elements will call itself. This will be the moment it will become
> hairy for you. When you reached this point: try it without apply for a
> few minutes. If you can't continue: use apply.
> Here is the first line:
> (defun nth-elements (n &rest lists)

That was fun.  I solved this using "eval" (ugh).

As a lemma to your assignment I've been trying to implement my own
version of apply (sort-of-apply) using macros.  I'm new to Lisp and I
haven't quite got the hang of writing even simple macros.  Here is what
I've come up with so far:

(defmacro sort-of-apply (fn lst)
  `(funcall ,fn ,@lst))

;; (1) it does not handle the case of (apply #'+ 1 2 (list 3 4)).  This
is fine for now
;; (2) quoted lists are not handled as desired.  Drat, how do I fix
this?

(sort-of-apply  #'+ '(1 2 3))  ==> (FUNCALL #'+ QUOTE (1 2 3))

(sort-of-apply  #'+ (1 2 3))   ==> (FUNCALL #'+ 1 2 3)


Cheers,
  --jfc
From: Kaz Kylheku
Subject: Re: When to use apply
Date: 
Message-ID: <1138125921.587652.61060@z14g2000cwz.googlegroups.com>
funkyj wrote:
> As a lemma to your assignment I've been trying to implement my own
> version of apply (sort-of-apply) using macros.  I'm new to Lisp and I
> haven't quite got the hang of writing even simple macros.  Here is what
> I've come up with so far:
>
> (defmacro sort-of-apply (fn lst)
>   `(funcall ,fn ,@lst))

You're allowed to call a variable LIST in Common Lisp.

> ;; (1) it does not handle the case of (apply #'+ 1 2 (list 3 4)).  This
> is fine for now
> ;; (2) quoted lists are not handled as desired.  Drat, how do I fix
> this?

All that your macro does is transform the syntax

  (sort-of-apply x (a b c ...))

into

  (funcall x a b c ...)

In other words, it's really a sort-of-funcall. Once the macro does its
job of expanding, the FUNCALL is fixed. Whenever you call that block of
code, it will be the same FUNCALL. Whereas the same instance of an
APPLY call can pass a different number of arguments on different
invocations.

You can't make APPLY out of FUNCALL without making use of run-time
evaluation or compilation of source code.

> (sort-of-apply  #'+ '(1 2 3))  ==> (FUNCALL #'+ QUOTE (1 2 3))

You could handle (QUOTE ...) and (LIST ...) by checking for these
operators in the macro body and applying an extra evaluation to them.
But that evaluation would take place at macro-expansion time.
From: André Thieme
Subject: Re: When to use apply
Date: 
Message-ID: <1138127679.412222.223310@g43g2000cwa.googlegroups.com>
funkyj schrieb:

> André Thieme wrote:
>
> > Try to write a function nth-elements which takes a number n and any
> > number of lists and returns a list of the nth's element of each list.
> >
> > (nth-elements 3 '(10 20 hello x world) '(-1 -2 -3 y) '(z0 z1 z2 z))  =>
> >  (x y z)
> >
> > Please make it a recursive function (without a loops, etc.).
> > When it is a recursive function you will come to the point where
> > nth-elements will call itself. This will be the moment it will become
> > hairy for you. When you reached this point: try it without apply for a
> > few minutes. If you can't continue: use apply.
> > Here is the first line:
> > (defun nth-elements (n &rest lists)
>
> That was fun.  I solved this using "eval" (ugh).

The "ugh" tells that you already heared that one should not use eval
very often and you probably suppose your use of eval was not necessary.
Well, you are right, one can do it without eval. But maybe you want to
post your code here anyway?

If you want you can try it without using eval.


> As a lemma to your assignment I've been trying to implement my own
> version of apply (sort-of-apply) using macros.  I'm new to Lisp and I
> haven't quite got the hang of writing even simple macros.  Here is what
> I've come up with so far:
>
> (defmacro sort-of-apply (fn lst)
>   `(funcall ,fn ,@lst))
>
> ;; (1) it does not handle the case of (apply #'+ 1 2 (list 3 4)).  This
> is fine for now
> ;; (2) quoted lists are not handled as desired.  Drat, how do I fix
> this?

Yes, this is a macro, so it takes your quoted lists unevaluated.


> (sort-of-apply  #'+ '(1 2 3))  ==> (FUNCALL #'+ QUOTE (1 2 3))

Yes, that is short for (sort-of-apply #'+ (quote (1 2 3)))

See this function:
(defun foo (x) x)
CL-USER> (foo '(1 2 3))
(1 2 3)
CL-USER> (foo (quote (1 2 3)))
(1 2 3)
CL-USER> (foo (quote (quote (1 2 3))))  ; === (foo ''(1 2 3))
(quote (1 2 3))

This last call is like the standard behaviour of macros.
When you call it like (sort-of-apply #'+ (quote (1 2 3))) then your
second argument is a list with two elements: the symbol "quote" and a
list containing 1, 2 and 3.

So you could try:
(defmacro sort-of-apply (fn lst)
  `(funcall ,fn ,@(second lst)))

CL-USER> (sort-of-apply #'+ '(10 20 30))
60


It is not easily possible to define your own version of apply.
Check out this thread:
http://groups.google.de/group/comp.lang.lisp/browse_frm/thread/6a8fbc8a73c59fcd/336f7f30a4464f0d?tvc=1&q=define+apply#336f7f30a4464f0d


André
--
From: funkyj
Subject: Re: When to use apply
Date: 
Message-ID: <1138130926.701331.20110@f14g2000cwb.googlegroups.com>
André Thieme wrote:
> funkyj schrieb:
>
> > As a lemma to your assignment I've been trying to implement my own
> > version of apply (sort-of-apply) using macros.  I'm new to Lisp and I
> > haven't quite got the hang of writing even simple macros.  Here is what
> > I've come up with so far:
> >
> > (defmacro sort-of-apply (fn lst)
> >   `(funcall ,fn ,@lst))
> >
> > ;; (1) it does not handle the case of (apply #'+ 1 2 (list 3 4)).  This
> > is fine for now
> > ;; (2) quoted lists are not handled as desired.  Drat, how do I fix
> > this?
>
> Yes, this is a macro, so it takes your quoted lists unevaluated.
>
> > (sort-of-apply  #'+ '(1 2 3))  ==> (FUNCALL #'+ QUOTE (1 2 3))
>
> Yes, that is short for (sort-of-apply #'+ (quote (1 2 3)))
>
> See this function:
> (defun foo (x) x)
> CL-USER> (foo '(1 2 3))
> (1 2 3)
> CL-USER> (foo (quote (1 2 3)))
> (1 2 3)
> CL-USER> (foo (quote (quote (1 2 3))))  ; === (foo ''(1 2 3))
> (quote (1 2 3))
>
> This last call is like the standard behaviour of macros.
> When you call it like (sort-of-apply #'+ (quote (1 2 3))) then your
> second argument is a list with two elements: the symbol "quote" and a
> list containing 1, 2 and 3.
>
> So you could try:
> (defmacro sort-of-apply (fn lst)
>   `(funcall ,fn ,@(second lst)))

Thanks, that works better!

> It is not easily possible to define your own version of apply.
> Check out this thread:
>http://groups.google.de/group/comp.lang.lisp/browse_frm/thread/6a8fbc8a73c59fcd/336f7f30a4464f0d?tvc=1&q=define+apply#336f7f30a4464f0d


Thank you, that thread is interesting.

BTW, here is a new version of (sort-of-apply) that works better:

    (defmacro sort-of-apply (fn lst)
      (let ((args (cond
                    ((and (= (length lst) 2) (eq 'quote (first lst)))
                     (second lst))
                    ((eq 'list (first lst))
                     (cdr lst))
                    (t lst))))
        `(funcall ,fn ,@args)))

    (sort-of-apply  #'+ '(1 2 3))    ==> (FUNCALL #'+ 1 2 3)

    (sort-of-apply  #'+ (1 2 3))     ==> (FUNCALL #'+ 1 2 3)

    (sort-of-apply #'+ (list 1 2 3)) ==> (FUNCALL #'+ 1 2 3)

how do we break this version?

  --jfc
From: Coby Beck
Subject: Re: When to use apply
Date: 
Message-ID: <AlwBf.94975$m05.44365@clgrps12>
"funkyj" <······@gmail.com> wrote in message 
····························@f14g2000cwb.googlegroups.com...
Andr� Thieme wrote:
> funkyj schrieb:
>
> > As a lemma to your assignment I've been trying to implement my own
> > version of apply (sort-of-apply) using macros.  I'm new to Lisp and I
> > haven't quite got the hang of writing even simple macros.  Here is what
> > I've come up with so far:
> >
> > (defmacro sort-of-apply (fn lst)
> >   `(funcall ,fn ,@lst))
> >
> > ;; (1) it does not handle the case of (apply #'+ 1 2 (list 3 4)).  This
> > is fine for now
> > ;; (2) quoted lists are not handled as desired.  Drat, how do I fix
> > this?
>
> Yes, this is a macro, so it takes your quoted lists unevaluated.
>
> > (sort-of-apply  #'+ '(1 2 3))  ==> (FUNCALL #'+ QUOTE (1 2 3))
>
> Yes, that is short for (sort-of-apply #'+ (quote (1 2 3)))
>
> See this function:
> (defun foo (x) x)
> CL-USER> (foo '(1 2 3))
> (1 2 3)
> CL-USER> (foo (quote (1 2 3)))
> (1 2 3)
> CL-USER> (foo (quote (quote (1 2 3))))  ; === (foo ''(1 2 3))
> (quote (1 2 3))
>
> This last call is like the standard behaviour of macros.
> When you call it like (sort-of-apply #'+ (quote (1 2 3))) then your
> second argument is a list with two elements: the symbol "quote" and a
> list containing 1, 2 and 3.
>
> So you could try:
> (defmacro sort-of-apply (fn lst)
>   `(funcall ,fn ,@(second lst)))

Thanks, that works better!

> It is not easily possible to define your own version of apply.
> Check out this thread:
>http://groups.google.de/group/comp.lang.lisp/browse_frm/thread/6a8fbc8a73c59fcd/336f7f30a4464f0d?tvc=1&q=define+apply#336f7f30a4464f0d


Thank you, that thread is interesting.

BTW, here is a new version of (sort-of-apply) that works better:

    (defmacro sort-of-apply (fn lst)
      (let ((args (cond
                    ((and (= (length lst) 2) (eq 'quote (first lst)))
                     (second lst))
                    ((eq 'list (first lst))
                     (cdr lst))
                    (t lst))))
        `(funcall ,fn ,@args)))

    (sort-of-apply  #'+ '(1 2 3))    ==> (FUNCALL #'+ 1 2 3)

    (sort-of-apply  #'+ (1 2 3))     ==> (FUNCALL #'+ 1 2 3)

    (sort-of-apply #'+ (list 1 2 3)) ==> (FUNCALL #'+ 1 2 3)

how do we break this version?
================================END QUOTE

Just pass it any other form besides (quote (...)) or (list ...) that returns 
a list.

A macro will never help you truly replace apply unless you macroexpand it at 
run time inside a helper function, which is just hiding the call to eval.

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Wade Humeniuk
Subject: Re: When to use apply
Date: 
Message-ID: <HqwBf.132618$6K2.65469@edtnps90>
funkyj wrote:

> 
> Thank you, that thread is interesting.
> 
> BTW, here is a new version of (sort-of-apply) that works better:
> 
>     (defmacro sort-of-apply (fn lst)
>       (let ((args (cond
>                     ((and (= (length lst) 2) (eq 'quote (first lst)))
>                      (second lst))
>                     ((eq 'list (first lst))
>                      (cdr lst))
>                     (t lst))))
>         `(funcall ,fn ,@args)))
> 
>     (sort-of-apply  #'+ '(1 2 3))    ==> (FUNCALL #'+ 1 2 3)
> 
>     (sort-of-apply  #'+ (1 2 3))     ==> (FUNCALL #'+ 1 2 3)
> 
>     (sort-of-apply #'+ (list 1 2 3)) ==> (FUNCALL #'+ 1 2 3)
> 
> how do we break this version?
> 
>   --jfc
> 

Easy,

(sort-of-apply  #'+ (mapcar 'identity '(1 2 3)))

Wade
From: Pascal Bourguignon
Subject: Re: When to use apply
Date: 
Message-ID: <874q3t4fqi.fsf@thalassa.informatimago.com>
"Andr� Thieme" <······························@justmail.de> writes:
> So you could try:
> (defmacro sort-of-apply (fn lst)
>   `(funcall ,fn ,@(second lst)))
>
> CL-USER> (sort-of-apply #'+ '(10 20 30))
> 60

This doesn't help when we want to use sort-of-apply for what apply is
needed:

(let ((list (list 10 20 30)))
   (sort-of-apply (function +) list)) --> error


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Kitty like plastic.
Confuses for litter box.
Don't leave tarp around.
From: Coby Beck
Subject: Re: When to use apply
Date: 
Message-ID: <ACuBf.94952$m05.75106@clgrps12>
"funkyj" <······@gmail.com> wrote in message 
·····························@g44g2000cwa.googlegroups.com...
>
>Andr� Thieme wrote:
>
>> Here is the first line:
>> (defun nth-elements (n &rest lists)
>
>That was fun.  I solved this using "eval" (ugh).
>
>As a lemma to your assignment I've been trying to implement my own
>version of apply (sort-of-apply) using macros.  I'm new to Lisp and I
>haven't quite got the hang of writing even simple macros.  Here is what
>I've come up with so far:
>
>(defmacro sort-of-apply (fn lst)
>  `(funcall ,fn ,@lst))
>
>;; (1) it does not handle the case of (apply #'+ 1 2 (list 3 4)).  This
>is fine for now
>;; (2) quoted lists are not handled as desired.  Drat, how do I fix
>this?
>
>(sort-of-apply  #'+ '(1 2 3))  ==> (FUNCALL #'+ QUOTE (1 2 3))
>
>(sort-of-apply  #'+ (1 2 3))   ==> (FUNCALL #'+ 1 2 3)

As you are doing this as a macro I think it is more appropriate that you do 
not use a quote when you call it.

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Pascal Bourguignon
Subject: Re: When to use apply
Date: 
Message-ID: <87zmll3116.fsf@thalassa.informatimago.com>
"funkyj" <······@gmail.com> writes:
> (defmacro sort-of-apply (fn lst)
>   `(funcall ,fn ,@lst))
>
> ;; (1) it does not handle the case of (apply #'+ 1 2 (list 3 4)).  This
> is fine for now
> ;; (2) quoted lists are not handled as desired.  Drat, how do I fix
> this?
>
> (sort-of-apply  #'+ '(1 2 3))  ==> (FUNCALL #'+ QUOTE (1 2 3))
>
> (sort-of-apply  #'+ (1 2 3))   ==> (FUNCALL #'+ 1 2 3)

As explained, you would write:

  (sort-of-apply  #'+ (1 2 3))

And you'd want to write, as with APPLY:

(let ((list (list 10 20 30)))
  (sort-of-apply (function +) list))

But then, it'd expand to:

(let ((list (list 10 20 30)))
  (funcall (function +) list))

and this wouldn't work because + expects numbers not lists.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Kitty like plastic.
Confuses for litter box.
Don't leave tarp around.
From: funkyj
Subject: Re: When to use apply
Date: 
Message-ID: <1138131596.695068.282520@g49g2000cwa.googlegroups.com>
Pascal Bourguignon wrote:

> (let ((list (list 10 20 30)))
>   (sort-of-apply (function +) list))
>
> But then, it'd expand to:
>
> (let ((list (list 10 20 30)))
>   (funcall (function +) list))
>
> and this wouldn't work because + expects numbers not lists.

Ah, that breaks the (sort-of-apply) in my previous posting :^).

Is it really not possible to define apply in terms of funcall or is it
just difficult (e.g. one of you experts can do it)?

Thanks,
  --jfc
From: Coby Beck
Subject: Re: When to use apply
Date: 
Message-ID: <qrwBf.94976$m05.35934@clgrps12>
"funkyj" <······@gmail.com> wrote in message 
·····························@g49g2000cwa.googlegroups.com...
>
> Pascal Bourguignon wrote:
>
>> (let ((list (list 10 20 30)))
>>   (sort-of-apply (function +) list))
>>
>> But then, it'd expand to:
>>
>> (let ((list (list 10 20 30)))
>>   (funcall (function +) list))
>>
>> and this wouldn't work because + expects numbers not lists.
>
> Ah, that breaks the (sort-of-apply) in my previous posting :^).
>
> Is it really not possible to define apply in terms of funcall or is it
> just difficult (e.g. one of you experts can do it)?

I can't think of any way without using eval or building and compiling 
something at runtime.  But I really hesitate to say "I can't do it" = "It is 
not possible"

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: funkyj
Subject: Re: When to use apply
Date: 
Message-ID: <1138153004.004794.317680@g49g2000cwa.googlegroups.com>
Coby Beck wrote:

> I can't think of any way without using eval or building and compiling
> something at runtime.  But I really hesitate to say "I can't do it" = "It is
> not possible"

 I factored out Pascal's (sort-of-apply #'+ L) case so that it uses
eval:

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; not quite apply.

    (defmacro sort-of-apply (fn lst)
      (let ((args (cond
                    ((not (listp lst)) (eval lst))
                    ((and (= (length lst) 2) (eq 'quote (first lst)))
                     (second lst))
                    ((eq 'list (first lst))
                     (cdr lst))
                    (t lst))))
        `(funcall ,fn ,@args)))

    (setf L '("setf, top level 'L'"))
    (defvar L2 '("defvar, top level 'L2'"))
    (defun expand-soa-tests ()
      (let* ((L '(1 2 3))
             (L2 '(1 2 3))
             (soa-tests '(
                          (sort-of-apply  #'+ '(1 2 3))
                          (sort-of-apply  #'+ (1 2 3))
                          (sort-of-apply #'+ (list 1 2 3))
                          (sort-of-apply #'+ L)
                          (sort-of-apply #'+ L2))))
        (format t "L ==> ~A~%~%" l)
        (dolist (x soa-tests 'DONE)
          (format t "~35A ==> ~A~%" x (macroexpand-1 x)))))

Here are the results:

    ; SLIME 2006-01-20
    ;;;; Compile file c:/cygwin/home/jcano/tests/clisp/exercise/cll_0
...
    ;; Compiling file
/cygdrive/c/cygwin/home/jcano/tests/clisp/exercise/cll_01/sort-of-apply.lisp
...
    WARNING in 14 25 (SETF L '("setf, top level 'L'"))-2 in lines
14..25 :
    L is neither declared nor bound,
    it will be treated as if it were declared SPECIAL.
    ;; Wrote file
/cygdrive/c/cygwin/home/jcano/tests/clisp/exercise/cll_01/sort-of-apply.fas
    ;; Loading file
/home/jcano/tests/clisp/exercise/cll_01/sort-of-apply.fas ...
        (expand-soa-tests)  ; show how the current `sort-of-apply'
                            ; macro expands given various input.
    ;; Loaded file
/home/jcano/tests/clisp/exercise/cll_01/sort-of-apply.fas
    0 errors, 1 warning

    CL-USER> (expand-soa-tests)
    L ==> (1 2 3)

    (SORT-OF-APPLY #'+ '(1 2 3))        ==> (FUNCALL #'+ 1 2 3)
    (SORT-OF-APPLY #'+ (1 2 3))         ==> (FUNCALL #'+ 1 2 3)
    (SORT-OF-APPLY #'+ (LIST 1 2 3))    ==> (FUNCALL #'+ 1 2 3)
    (SORT-OF-APPLY #'+ L)               ==> (FUNCALL #'+ setf, top
level 'L')
    (SORT-OF-APPLY #'+ L2)              ==> (FUNCALL #'+ 1 2 3)
    DONE


As you can see, it mostly works with some anomalous behavior when the
symbol being evaluated is "declared special" (see compiler warning
above).

In any event I think I've proved to myself how much more difficult it
is to implement 'apply' in terms of 'funcall' rather than vice versa.

Cheers,
  -jfc
From: André Thieme
Subject: Re: When to use apply
Date: 
Message-ID: <1138156180.105626.237310@g44g2000cwa.googlegroups.com>
funkyj schrieb:

> Coby Beck wrote:
>
> > I can't think of any way without using eval or building and compiling
> > something at runtime.  But I really hesitate to say "I can't do it" = "It is
> > not possible"
>
>  I factored out Pascal's (sort-of-apply #'+ L) case so that it uses
> eval:
>
>     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>     ;; not quite apply.
>
>     (defmacro sort-of-apply (fn lst)
>       (let ((args (cond
>                     ((not (listp lst)) (eval lst))
>                     ((and (= (length lst) 2) (eq 'quote (first lst)))
>                      (second lst))
>                     ((eq 'list (first lst))
>                      (cdr lst))
>                     (t lst))))
>         `(funcall ,fn ,@args)))

You already said it: not quite apply.


> As you can see, it mostly works with some anomalous behavior when the
> symbol being evaluated is "declared special" (see compiler warning above).

Lisp did not know the symbol you wanted to setf. This only works
because clisp is so friendly to create a special variable for you.
Instead of setf you could use defparameter.


> In any event I think I've proved to myself how much more difficult it
> is to implement 'apply' in terms of 'funcall' rather than vice versa.

Yes, it really is difficult.
CL-USER> (apply #'append '(nil (1 2)))
(1 2)

CL-USER> (sort-of-apply #'append '(nil (1 2)))
; in: LAMBDA NIL
;     (1 2)
;
; caught ERROR:
;   illegal function call
;
; compilation unit finished
;   caught 1 ERROR condition
; Evaluation aborted


Now that you learned more about apply you could try to implement
nth-elements without using eval.


André
--
From: Pascal Bourguignon
Subject: Re: When to use apply
Date: 
Message-ID: <87y8141zhs.fsf@thalassa.informatimago.com>
"funkyj" <······@gmail.com> writes:

> Coby Beck wrote:
>
>> I can't think of any way without using eval or building and compiling
>> something at runtime.  But I really hesitate to say "I can't do it" = "It is
>> not possible"
>
>  I factored out Pascal's (sort-of-apply #'+ L) case so that it uses
> eval:
>
>     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>     ;; not quite apply.
>
>     (defmacro sort-of-apply (fn lst)
>       (let ((args (cond
>                     ((not (listp lst)) (eval lst))

You are evaluating lst at macroexpansion time.
In this case, when lst may  bound to a non nil symbol or another atom,
and this symbol or atom is bound to args; nothing is done.


> [...]
> As you can see, it mostly works with some anomalous behavior when the
> symbol being evaluated is "declared special" (see compiler warning
> above).

It's the contrary: it's when the variable is lexical that problems
occur, because EVAL cannot access it (CL:EVAL doesn't take an
environment argument).


Slightly better, but still useless:


(defmacro sort-of-apply (fn lst)
  (cond
    ((symbolp lst)           ;a variable, it's value should be a list.
     `(eval (list* 'funcall ,fn (mapcar (lambda (item) (list 'quote item)) ,lst))))
    ((atom lst) `(funcall ,fn ',lst))
    ((and (= (length lst) 2) (eq 'quote (first lst)))
     `(sort-of-apply ,fn ,(second lst)))
    ((eq 'list (first lst))
     `(sort-of-apply ,fn ,(cdr lst)))
    (t
     `(funall ,fn ,@lst))))



(setf L '("setf, top level 'L'"))
(defvar L2 '("defvar, top level 'L2'"))
(defvar L3 '(L L2 1 #(2 3) "Ha!"))
(defun expand-soa-tests ()
  (let* ((L '(1 2 3))
         (L2 '(1 2 3))
         (L3 '(dynamically not top-level L L2 1 #(2 3) "Ha!"))
         (L4 '(only-lexically L L2 1 #(2 3) "Ha!"))
         (soa-tests '(
                      (sort-of-apply  #'+ '(1 2 3))
                      (sort-of-apply  #'+ (1 2 3))
                      (sort-of-apply #'+ (list 1 2 3))
                      (sort-of-apply #'+ L)
                      (sort-of-apply #'+ L2)
                      (sort-of-apply #'+ L3)
                      (sort-of-apply #'+ L4))))
    (format t "L ==> ~S~%~%" l)
    (dolist (x soa-tests 'DONE)
      (handler-case
          (progn
      (format t "~%~35A ==> ~S~%" x (macroexpand-1 x))
      (when (eq 'sort-of-apply (car (macroexpand-1 x)))
        (format t "~35A ==> ~S~%" x (macroexpand   x)))
      (when (eq 'eval (car (macroexpand-1 x)))
        (format t "~35A ==> ~S~%" x (list 'eval
                                          (eval (second (macroexpand-1 x)))))))
        (error (err) (princ err))))))

[36]> ( expand-soa-tests)
L ==> (1 2 3)


(SORT-OF-APPLY #'+ '(1 2 3))        ==> (SORT-OF-APPLY #'+ (1 2 3))
(SORT-OF-APPLY #'+ '(1 2 3))        ==> (FUNALL #'+ 1 2 3)

(SORT-OF-APPLY #'+ (1 2 3))         ==> (FUNALL #'+ 1 2 3)

(SORT-OF-APPLY #'+ (LIST 1 2 3))    ==> (SORT-OF-APPLY #'+ (1 2 3))
(SORT-OF-APPLY #'+ (LIST 1 2 3))    ==> (FUNALL #'+ 1 2 3)

(SORT-OF-APPLY #'+ L)               ==> (EVAL (LIST* 'FUNCALL #'+ (MAPCAR (LAMBDA (ITEM) (LIST 'QUOTE ITEM)) L)))
(SORT-OF-APPLY #'+ L)               ==> (EVAL (FUNCALL #<SYSTEM-FUNCTION +> '"setf, top level 'L'"))

(SORT-OF-APPLY #'+ L2)              ==> (EVAL (LIST* 'FUNCALL #'+ (MAPCAR (LAMBDA (ITEM) (LIST 'QUOTE ITEM)) L2)))
(SORT-OF-APPLY #'+ L2)              ==> (EVAL (FUNCALL #<SYSTEM-FUNCTION +> '1 '2 '3))

(SORT-OF-APPLY #'+ L3)              ==> (EVAL (LIST* 'FUNCALL #'+ (MAPCAR (LAMBDA (ITEM) (LIST 'QUOTE ITEM)) L3)))
(SORT-OF-APPLY #'+ L3)              ==> 
(EVAL
 (FUNCALL #<SYSTEM-FUNCTION +> 'DYNAMICALLY 'NOT 'TOP-LEVEL 'L 'L2 '1 '#(2 3)
  '"Ha!"))

(SORT-OF-APPLY #'+ L4)              ==> (EVAL (LIST* 'FUNCALL #'+ (MAPCAR (LAMBDA (ITEM) (LIST 'QUOTE ITEM)) L4)))
EVAL: variable L4 has no value
DONE
[37]> 



> In any event I think I've proved to myself how much more difficult it
> is to implement 'apply' in terms of 'funcall' rather than vice versa.

It's impossible.  That's why EVAL and APPLY are the primitives, 
not EVAL and FUNCALL.

Read at least chapter 4 of SICP.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Cats meow out of angst
"Thumbs! If only we had thumbs!
We could break so much!"
From: Wade Humeniuk
Subject: Re: When to use apply
Date: 
Message-ID: <UEwBf.132630$6K2.132256@edtnps90>
Coby Beck wrote:

> 
> I can't think of any way without using eval or building and compiling 
> something at runtime.  But I really hesitate to say "I can't do it" = "It is 
> not possible"
> 

Though this cheats and does not use funcall

(defmacro sort-of-apply (function list)
   `(multiple-value-call ,function (values-list ,list)))

Internally multiple-value-call uses apply.

Wade
From: drewc
Subject: Re: When to use apply
Date: 
Message-ID: <87oe203gob.fsf@rift.com>
"funkyj" <······@gmail.com> writes:


>
> Is it really not possible to define apply in terms of funcall or is it
> just difficult (e.g. one of you experts can do it)?

On small-cl-src[1], Andreas Fuchs posted an implementation of APPLY in
terms of funcall.

I've pasted that below :

(defun apply-definer (max-args)
  `(defun apply-1 (f args)
     (case (length args)
       ,@(loop for arg-count from 0 to max-args
	       collect `((,arg-count)
			 (funcall
			   f
			   ,@(loop for arg-idx from 0 to (1- arg-count)
				   collect `(nth ,arg-idx args)))))
       (otherwise
	(error ,(format nil "Can't apply to more than ~A args" max-args))))))

(defmacro define-apply (max-args)
  (apply-definer (etypecase max-args
		   (symbol (symbol-value max-args))
		   (number max-args))))

(defun my-apply (f &rest args)
	   (let ((last-arg (first (last args))))
	     (apply-1 f 
		      (if (listp last-arg)
			  (append (butlast args) last-arg)
			  args))))

(define-apply ; call-arguments-limit  ; might be a bit much for the poor impl
              20                      ; let's be humane
	      )

;;; example:

#|
CL-USER> (defun print-all (&rest args) (loop for arg in args  do (print arg)))

CL-USER> (my-apply #'print-all 1 2 3 '(1 2 3))

1 
2 
3 
1 
2 
3 

NIL
|#

hope that helps
drewc


-- 
drewc at tech dot coop
[1] http://www.cliki.net/small-cl-src