From: Christopher Dollin
Subject: Composition/Partapply in CL Question
Date: 
Message-ID: <1350002@otter.HP.COM>
Another question about doing things in CL!

If p and q are functions with arbitrary in-arity and out-arity, what is the
idiomatic efficient way of writing a function 

    (compose p q)

which delivers a function that when applied, applies q to the result of 
applying p to the argument?

    (defun compose (p q)
        #'(lambda (&rest args)
            (multiple-value-call q (apply p args))
        )
    )

is the obvious solution. Would implementors like to comment on its efficiency?
Similarly if p is a function, what is an idiomatic or efficient way to define

    (partapply p a1 ... an)

which produces a function which, when applied to arguments b1 ... bn, applies
p to a1 ... an b1 ... bn.

    (defun partapply (p &rest args)
        #'(lambda (&rest more)
            (apply p (append args more))
        )
    )

should work but it certainly doesn't LOOK efficient ...

Regards,
Kers                                    | "Why Lisp if you can talk Poperly?"

From: Barry Margolin
Subject: Re: Composition/Partapply in CL Question
Date: 
Message-ID: <13984@think.UUCP>
In article <·······@otter.HP.COM> ····@otter.HP.COM (Christopher Dollin) writes:
>Another question about doing things in CL!

Even if your questions were silly (which they aren't), it's just such
a refreshing break to see stuff in this newsgroup that isn't flames...

>    (defun compose (p q)
>        #'(lambda (&rest args)
>            (multiple-value-call q (apply p args))
>        )
>    )
>
>is the obvious solution. Would implementors like to comment on its efficiency?

That looks right to me.  If you are willing to let COMPOSE be a macro
instead of a function, then you could do:

(defmacro compose (p q)
  `#'(lambda (&rest args)
       (apply ,q (multiple-value-list (apply ,p args)))))

The only advantage this has is that it doesn't need to create a
lexical closure to capture the local values of P and Q.  However, this
only conses a couple of words in the implementations I'm familiar
with; in general, one needn't be afraid of returning lexical closures.

>    (Defun partapply (p &rest args)
>        #'(lambda (&rest more)
>            (apply p (append args more))
>        )
>    )
>
>should work but it certainly doesn't LOOK efficient ...

This one can definitely be made more efficient by being a macro,
because then it doesn't have to do the APPEND at run time.

(defmacro partapply (p &rest args)
  `#'(lambda (&rest more)
       (apply ,p ,@args more)))

This isn't precisely correct, though, because it will evaluate the
args at the time the resulting function is called rather than when
partapply is called.  For example

(defun my-+ (a b)
  (let ((test-function (partapply #'+ a)))
    (setq a 0)
    (apply test-function b)))

It's difficult to get it right, so your solution is probably what I
would use.  Symbolics has some code that tries to do something like
the above right; their solution was to expand into a LET that binds
all the free variables to their current values, and return a closure
in that environment (they call this "snapshotting" the environment),
but it has the problem that if the code modifies one of the
snapshotted variables the change isn't seen outside the snapshot
environment.

(do ((i 1 (1+ i)))
    ((> i 10))
  (snapshot-variables
    (setq i (1+ i))))



---
Barry Margolin
Thinking Machines Corp.

······@think.com
seismo!think!barmar
From: Christopher Dollin
Subject: Re: Composition/Partapply in CL Question
Date: 
Message-ID: <1350004@otter.HP.COM>
One problem with using lexical variables freely (as in compose in the basenote)
is that although it may cons only a few words, the resulting closure may 
contain pointers to unused but arbitrarily large structures, thus permitting
garbage to be retained way part its normal collection. I'm afraid I don't
know enough about Lisp implementation to know if this is likely to be a 
problem: how is the environment usually represented?

[In the case of Pop11, lexical closures are implemented as concealed partial
applications, like lambda-lifting; hence no extra garbage is retained, but
the closure is more expensive to compute. It conses store by something like

    fixed overhead + 2 * number of free variables

where the fixed overhead is that for a simple procedure plus call to the
part-applyed procedure, and each free variable contributes some store for
the indirection headers and some for the instruction to push it as an argument.
If I have messed up the description I apologise in advance to John Gibson
and the rest of the Poplog team!]

Regards,
Kers.                               | "Why Lisp if you can talk Poperly?"