From: Erann Gat
Subject: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <gat-1108031242430001@k-137-79-50-101.jpl.nasa.gov>
Is there a way to achieve the following in partable CL:

(defmacro call-with-values (function form) ...)

(defun foo (x y) (list x y))

(call-with-values #'foo 1) --> (1 nil)
(call-with-values #'foo (values 1 2 3)) --> (1 2)

(The reason I want to do this is that I want to be write a my-maphash
function that can map functions of either 1 or 2 arguments.)

E.

From: Barry Margolin
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <LCSZa.1$mD.0@news.level3.com>
In article <····················@k-137-79-50-101.jpl.nasa.gov>,
Erann Gat <···@jpl.nasa.gov> wrote:
>
>Is there a way to achieve the following in partable CL:
>
>(defmacro call-with-values (function form) ...)
>
>(defun foo (x y) (list x y))
>
>(call-with-values #'foo 1) --> (1 nil)
>(call-with-values #'foo (values 1 2 3)) --> (1 2)
>
>(The reason I want to do this is that I want to be write a my-maphash
>function that can map functions of either 1 or 2 arguments.)

CALL-WITH-VALUES looks like a one-argument version of MULTIPLE-VALUE-CALL.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Erann Gat
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <gat-1108031344100001@k-137-79-50-101.jpl.nasa.gov>
In article <············@news.level3.com>, Barry Margolin
<··············@level3.com> wrote:

> In article <····················@k-137-79-50-101.jpl.nasa.gov>,
> Erann Gat <···@jpl.nasa.gov> wrote:
> >
> >Is there a way to achieve the following in partable CL:
> >
> >(defmacro call-with-values (function form) ...)
> >
> >(defun foo (x y) (list x y))
> >
> >(call-with-values #'foo 1) --> (1 nil)
> >(call-with-values #'foo (values 1 2 3)) --> (1 2)
> >
> >(The reason I want to do this is that I want to be write a my-maphash
> >function that can map functions of either 1 or 2 arguments.)
> 
> CALL-WITH-VALUES looks like a one-argument version of MULTIPLE-VALUE-CALL.

No.

Replacing call-with-values in the examples above with multiple-value-call
results in errors.

MULTIPLE-VALUE-CALL is the same as:

(defmacro m-v-c (function &rest args)
  `(apply ,function
          (apply 'append 
                 (list ,@(mapcar (lambda (arg) `(multiple-value-list ,arg))
                                 args)))))

You must provide the correct number of arguments.

What I want is something which is to multiple-value-bind as funcall is to
let.  I want call-with-values to automatically fill in missing arguments
and ignore extra ones just like multiple-value-bind does.

E.
From: Kalle Olavi Niemitalo
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <87smo8c4pe.fsf@Astalo.kon.iki.fi>
Barry Margolin <··············@level3.com> writes:

> CALL-WITH-VALUES looks like a one-argument version of MULTIPLE-VALUE-CALL.

Not quite; it also truncates or extends the list of values to
match the lambda list of the function.  The lambda list might be
retrievable with FUNCTION-LAMBDA-EXPRESSION, but then again it
might not.

In general, I don't quite like calling a function in different
ways depending on the lambda list, because that might not tell
the whole truth about the function.  It might have (&REST ARGS)
and parse everything on its own, for example.  With proper
documentation and just one or two arguments, the scheme could
work though -- assuming you can get the lambda list in the first
place.

:ALLOW-OTHER-KEYS is a somewhat similar feature; can you (Gat)
use that instead?
From: Erann Gat
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <gat-1108031400560001@k-137-79-50-101.jpl.nasa.gov>
In article <··············@Astalo.kon.iki.fi>, Kalle Olavi Niemitalo
<···@iki.fi> wrote:

> Barry Margolin <··············@level3.com> writes:
> 
> > CALL-WITH-VALUES looks like a one-argument version of MULTIPLE-VALUE-CALL.
> 
> Not quite; it also truncates or extends the list of values to
> match the lambda list of the function.  The lambda list might be
> retrievable with FUNCTION-LAMBDA-EXPRESSION, but then again it
> might not.
> 
> In general, I don't quite like calling a function in different
> ways depending on the lambda list, because that might not tell
> the whole truth about the function.  It might have (&REST ARGS)
> and parse everything on its own, for example.  With proper
> documentation and just one or two arguments, the scheme could
> work though -- assuming you can get the lambda list in the first
> place.
> 
> :ALLOW-OTHER-KEYS is a somewhat similar feature; can you (Gat)
> use that instead?

I don't think so.  Like I said in the OP, I want to write a function that
does what MAPHASH does, but can take functions of 1 argument as well as
2.  I can't think of any way that :allow-other-keys would help.

E.
From: Barry Margolin
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <dvTZa.7$mD.5@news.level3.com>
In article <····················@k-137-79-50-101.jpl.nasa.gov>,
Erann Gat <···@jpl.nasa.gov> wrote:
>(The reason I want to do this is that I want to be write a my-maphash
>function that can map functions of either 1 or 2 arguments.)

I don't think it's possible to do what you want portably.  So for this
particular purpose, I suggest either:

* Write two functions, my-maphash-1 and my-maphash-2; the user calls the
  one appropriate for the number of arguments their function takes.

* Write a function that takes a flag argument indicating whether the
  function takes 1 or 2 arguments.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Erann Gat
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <gat-1108031430340001@k-137-79-50-101.jpl.nasa.gov>
In article <············@news.level3.com>, Barry Margolin
<··············@level3.com> wrote:

> In article <····················@k-137-79-50-101.jpl.nasa.gov>,
> Erann Gat <···@jpl.nasa.gov> wrote:
> >(The reason I want to do this is that I want to be write a my-maphash
> >function that can map functions of either 1 or 2 arguments.)
> 
> I don't think it's possible to do what you want portably.  So for this
> particular purpose, I suggest either:
> 
> * Write two functions, my-maphash-1 and my-maphash-2; the user calls the
>   one appropriate for the number of arguments their function takes.
>
> * Write a function that takes a flag argument indicating whether the
>   function takes 1 or 2 arguments.

Won't work.  The identity of the functions being mapped are bit known
until run-time.  (If I knew what functions were being mapped at
code-writing-time this whole thing would obviously not be an issue.)

E.
From: Erann Gat
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <gat-1108031442440001@k-137-79-50-101.jpl.nasa.gov>
In article <····················@k-137-79-50-101.jpl.nasa.gov>,
···@jpl.nasa.gov (Erann Gat) wrote:

> In article <············@news.level3.com>, Barry Margolin
> <··············@level3.com> wrote:
> 
> > In article <····················@k-137-79-50-101.jpl.nasa.gov>,
> > Erann Gat <···@jpl.nasa.gov> wrote:
> > >(The reason I want to do this is that I want to be write a my-maphash
> > >function that can map functions of either 1 or 2 arguments.)
> > 
> > I don't think it's possible to do what you want portably.  So for this
> > particular purpose, I suggest either:
> > 
> > * Write two functions, my-maphash-1 and my-maphash-2; the user calls the
> >   one appropriate for the number of arguments their function takes.
> >
> > * Write a function that takes a flag argument indicating whether the
> >   function takes 1 or 2 arguments.
> 
> Won't work.  The identity of the functions being mapped are bit known

That should, of course, have been "... are NOT known".

> until run-time.  (If I knew what functions were being mapped at
> code-writing-time this whole thing would obviously not be an issue.)
> 
> E.
From: Barry Margolin
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <BnUZa.13$mD.6@news.level3.com>
In article <····················@k-137-79-50-101.jpl.nasa.gov>,
Erann Gat <···@jpl.nasa.gov> wrote:
>In article <············@news.level3.com>, Barry Margolin
><··············@level3.com> wrote:
>
>> In article <····················@k-137-79-50-101.jpl.nasa.gov>,
>> Erann Gat <···@jpl.nasa.gov> wrote:
>> >(The reason I want to do this is that I want to be write a my-maphash
>> >function that can map functions of either 1 or 2 arguments.)
>> 
>> I don't think it's possible to do what you want portably.  So for this
>> particular purpose, I suggest either:
>> 
>> * Write two functions, my-maphash-1 and my-maphash-2; the user calls the
>>   one appropriate for the number of arguments their function takes.
>>
>> * Write a function that takes a flag argument indicating whether the
>>   function takes 1 or 2 arguments.
>
>Won't work.  The identity of the functions being mapped are bit known
>until run-time.  (If I knew what functions were being mapped at
>code-writing-time this whole thing would obviously not be an issue.)

They're being passed as arguments to some function, right?  Make two
versions of, or add a flag argument to, *that* function.  And so on and so
on.  Eventually you'll get to the caller that knows the identity of the
function.  If it's coming from a global variable, then you need a second
variable indicating the arity of the function.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: james anderson
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <3F381D08.ED1F54BB@setf.de>
Barry Margolin wrote:
> 
> ...
> 
> They're being passed as arguments to some function, right?  Make two
> versions of, or add a flag argument to, *that* function.  And so on and so
> on.  Eventually you'll get to the caller that knows the identity of the
> function.  If it's coming from a global variable, then you need a second
> variable indicating the arity of the function.

if the functions themselves have global definitions, what would argue against
requiring that they be passed by name. which would give the caller the
opportunity to communicate the arity of the function to my-maphash.

?
From: Barry Margolin
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <jgVZa.14$mD.4@news.level3.com>
In article <·················@setf.de>,
james anderson  <··············@setf.de> wrote:
>
>
>Barry Margolin wrote:
>> 
>> ...
>> 
>> They're being passed as arguments to some function, right?  Make two
>> versions of, or add a flag argument to, *that* function.  And so on and so
>> on.  Eventually you'll get to the caller that knows the identity of the
>> function.  If it's coming from a global variable, then you need a second
>> variable indicating the arity of the function.
>
>if the functions themselves have global definitions, what would argue against
>requiring that they be passed by name. which would give the caller the
>opportunity to communicate the arity of the function to my-maphash.

How would passing them by name provide the arity?

Since CL in general doesn't make it easy to call functions whose arity you
don't know with an argument list that you construct, why is the API that
you're implementing set up to accept functions that can take either 1 or 2
arguments?  Like MAPHASH, it should probably require a 2-argument function;
if the caller only cares about the first argument, he'll have to provide a
2-arg function that ignores the second argument.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: james anderson
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <3F38314A.62703190@setf.de>
Barry Margolin wrote:
> 
> In article <·················@setf.de>,
> james anderson  <··············@setf.de> wrote:
> ...
> >if the functions themselves have global definitions, what would argue against
> >requiring that they be passed by name. which would give the caller the
> >opportunity to communicate the arity of the function to my-maphash.
> 
> How would passing them by name provide the arity?

not intrinsically, but i was wondering about the practice of annotating the
name to provide the information. it just occurred to me, however, that one
cannot presume that symbol properties are retained in a compiled file.

> 
> Since CL in general doesn't make it easy to call functions whose arity [one
> does not] know with an argument list that [one] construct[s], why [set up an] API
> [] to accept functions that can take either 1 or 2
> arguments? ... [i'm not "doing" it. i'm just curious.]
> 

...
From: Barry Margolin
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <_A6_a.27$mD.7@news.level3.com>
In article <·················@setf.de>,
james anderson  <··············@setf.de> wrote:
>
>
>Barry Margolin wrote:
>> 
>> In article <·················@setf.de>,
>> james anderson  <··············@setf.de> wrote:
>> ...
>> >if the functions themselves have global definitions, what would argue against
>> >requiring that they be passed by name. which would give the caller the
>> >opportunity to communicate the arity of the function to my-maphash.
>> 
>> How would passing them by name provide the arity?
>
>not intrinsically, but i was wondering about the practice of annotating the
>name to provide the information. it just occurred to me, however, that one
>cannot presume that symbol properties are retained in a compiled file.

If the property is attached to the symbol by a top-level statement in the
file, loading it will perform that.  E.g.

(defun foo (a b) ...)
(setf (get 'foo 'arity) 2)

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Kent M Pitman
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <sfwfzk7h8fw.fsf@shell01.TheWorld.com>
···@jpl.nasa.gov (Erann Gat) writes:

> In article <············@news.level3.com>, Barry Margolin
> <··············@level3.com> wrote:
> 
> > In article <····················@k-137-79-50-101.jpl.nasa.gov>,
> > Erann Gat <···@jpl.nasa.gov> wrote:
> > >(The reason I want to do this is that I want to be write a my-maphash
> > >function that can map functions of either 1 or 2 arguments.)
> > 
> > I don't think it's possible to do what you want portably.  So for this
> > particular purpose, I suggest either:
> > 
> > * Write two functions, my-maphash-1 and my-maphash-2; the user calls the
> >   one appropriate for the number of arguments their function takes.
> >
> > * Write a function that takes a flag argument indicating whether the
> >   function takes 1 or 2 arguments.
> 
> Won't work.  The identity of the functions being mapped are bit known
> until run-time.  (If I knew what functions were being mapped at
> code-writing-time this whole thing would obviously not be an issue.)

This has nothing to do with values.  MULTIPLE-VALUE-CALL already manages
the values part.  The real question is masking unwanted questions and
totally has to do with knowing what arguments something takes.  There's
nothing in CL that (reliably) tells you what arguments something takes.
Most implementations have ARGLIST, FUNCTION-ARGLIST, or FUNCTION-LAMBDA-LIST,
though.  From those you could do the right thing.

- - - - 

I'm led to ask:

"What are you REALLY trying to do?"
From: james anderson
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <3F3818E6.41A241DF@setf.de>
Erann Gat wrote:
> ...
> 
> Won't work.  The identity of the functions being mapped are [not] known
> until run-time.  (If I knew what functions were being mapped at
> code-writing-time this whole thing would obviously not be an issue.)
> 

if you can constrain the function to be generic and you can work-around clos
variations, then you could examine the function in light of the key and value
types present in the hashtable and generate an appropriate wrapper to feed the
function the argument(s) key / data / (data x key) / (key x data) or whatever
you can figure out that the function can build an effective method for.

...
From: Christophe Rhodes
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <sqbruvj3ow.fsf@lambda.jcn.srcf.net>
···@jpl.nasa.gov (Erann Gat) writes:

> Is there a way to achieve the following in partable CL:
>
> (defmacro call-with-values (function form) ...)
>
> (defun foo (x y) (list x y))
>
> (call-with-values #'foo 1) --> (1 nil)
> (call-with-values #'foo (values 1 2 3)) --> (1 2)
>
> (The reason I want to do this is that I want to be write a my-maphash
> function that can map functions of either 1 or 2 arguments.)

(defmacro call-with-values (function maybe-values-form)
  `(flet ((fn (a &optional b &rest ignore)
            (declare (ignore ignore))
            (funcall ,function a b)))
     (declare (dynamic-extent fn))
     (multiple-value-call #'fn ,maybe-values-form)))

Cheers,

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Erann Gat
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <gat-1108031441110001@k-137-79-50-101.jpl.nasa.gov>
In article <··············@lambda.jcn.srcf.net>, Christophe Rhodes
<·····@cam.ac.uk> wrote:

> ···@jpl.nasa.gov (Erann Gat) writes:
> 
> > Is there a way to achieve the following in partable CL:
> >
> > (defmacro call-with-values (function form) ...)
> >
> > (defun foo (x y) (list x y))
> >
> > (call-with-values #'foo 1) --> (1 nil)
> > (call-with-values #'foo (values 1 2 3)) --> (1 2)
> >
> > (The reason I want to do this is that I want to be write a my-maphash
> > function that can map functions of either 1 or 2 arguments.)
> 
> (defmacro call-with-values (function maybe-values-form)
>   `(flet ((fn (a &optional b &rest ignore)
>             (declare (ignore ignore))
>             (funcall ,function a b)))
>      (declare (dynamic-extent fn))
>      (multiple-value-call #'fn ,maybe-values-form)))
> 
> Cheers,
> 
> Christophe

Nope.

? (defmacro call-with-values (function maybe-values-form)
  `(flet ((fn (a &optional b &rest ignore)
            (declare (ignore ignore))
            (funcall ,function a b)))   <----- Bzzzt
     (declare (dynamic-extent fn))
     (multiple-value-call #'fn ,maybe-values-form)))
CALL-WITH-VALUES
? (call-with-values #'foo 1)
;Compiler warnings :
;   Function call arguments don't match current definition of FOO, in FN
inside an anonymous lambda form.
> Error: Too many arguments (no opt/rest)
> While executing: FOO
> Type Command-. to abort.
See the Restarts� menu item for further choices.
1 > 

E.
From: Christophe Rhodes
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <sq3cg7i8e6.fsf@lambda.jcn.srcf.net>
···@jpl.nasa.gov (Erann Gat) writes:

> In article <··············@lambda.jcn.srcf.net>, Christophe Rhodes
> <·····@cam.ac.uk> wrote:
>
>> ···@jpl.nasa.gov (Erann Gat) writes:
>> 
>> > Is there a way to achieve the following in partable CL:
>> >
>> > (defmacro call-with-values (function form) ...)
>> >
>> > (defun foo (x y) (list x y))
>> >
>> > (call-with-values #'foo 1) --> (1 nil)
>> > (call-with-values #'foo (values 1 2 3)) --> (1 2)
>> >
>> > (The reason I want to do this is that I want to be write a my-maphash
>> > function that can map functions of either 1 or 2 arguments.)
>> 
>> (defmacro call-with-values (function maybe-values-form)
>>   `(flet ((fn (a &optional b &rest ignore)
>>             (declare (ignore ignore))
>>             (funcall ,function a b)))
>>      (declare (dynamic-extent fn))
>>      (multiple-value-call #'fn ,maybe-values-form)))
>> 
>> Cheers,
>> 
>> Christophe
>
> Nope.
>
> ? (defmacro call-with-values (function maybe-values-form)
>   `(flet ((fn (a &optional b &rest ignore)
>             (declare (ignore ignore))
>             (funcall ,function a b)))   <----- Bzzzt
>      (declare (dynamic-extent fn))
>      (multiple-value-call #'fn ,maybe-values-form)))
> CALL-WITH-VALUES
> ? (call-with-values #'foo 1)
> ;Compiler warnings :
> ;   Function call arguments don't match current definition of FOO, in FN
> inside an anonymous lambda form.
>> Error: Too many arguments (no opt/rest)
>> While executing: FOO
>> Type Command-. to abort.
> See the Restarts menu item for further choices.
> 1 > 

Perhaps you want to refine your specification, then, because my
solution works on your examples?  Let's see... assuming your examples
are nonsequiturs and I should instead divine your specification by
magic... ;-)

(defmacro call-with-values (function maybe-values-form)
  `(locally 
     ;; see CLHS 3.5.1
     (declare (optimize (safety 3)))
     (let ((values-list (multiple-value-list ,maybe-values-form)))
       (handler-case
           (flet ((fn (&optional a b &rest ignore)
                    (declare (ignore ignore))
                    (funcall ,function a b)))
             (declare (dynamic-extent #'fn))
             (multiple-value-call #'fn (values-list values-list)))
         (program-error ()
           (flet ((fn (&optional a ignore)
                    (declare (ignore ignore))
                    (funcall ,function a)))
             (declare (dynamic-extent #'fn))
             (multiple-value-call #'fn (values-list values-list))))))))

* (defun foo (x y) (list x y)) -> FOO

* (call-with-values #'foo 1) -> (1 NIL)

* (call-with-values #'foo (values 1 2 3)) -> (1 2)

* (defun bar (x) (list x)) -> BAR

* (call-with-values #'bar 1) -> (1)

* (call-with-values #'bar (values 1 2 3)) -> (1)

Cheers,

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Barry Margolin
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <mC6_a.29$mD.23@news.level3.com>
In article <··············@lambda.jcn.srcf.net>,
Christophe Rhodes  <·····@cam.ac.uk> wrote:
>Perhaps you want to refine your specification, then, because my
>solution works on your examples?  Let's see... assuming your examples
>are nonsequiturs and I should instead divine your specification by
>magic... ;-)

Does it take magic to read the text of his original post:

>>> > (The reason I want to do this is that I want to be write a my-maphash
>>> > function that can map functions of either 1 or 2 arguments.)

?

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Christophe Rhodes
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <sqlltyhp3o.fsf@lambda.jcn.srcf.net>
Barry Margolin <··············@level3.com> writes:

> In article <··············@lambda.jcn.srcf.net>,
> Christophe Rhodes  <·····@cam.ac.uk> wrote:
>>Perhaps you want to refine your specification, then, because my
>>solution works on your examples?  Let's see... assuming your examples
>>are nonsequiturs and I should instead divine your specification by
>>magic... ;-)
>
> Does it take magic to read the text of his original post:
>
>>>> > (The reason I want to do this is that I want to be write a my-maphash
>>>> > function that can map functions of either 1 or 2 arguments.)
>
> ?

No. ";-)"

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Pascal Costanza
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <costanza-EAE42B.23402911082003@news.netcologne.de>
In article <····················@k-137-79-50-101.jpl.nasa.gov>,
 ···@jpl.nasa.gov (Erann Gat) wrote:

> Is there a way to achieve the following in partable CL:
> 
> (defmacro call-with-values (function form) ...)
> 
> (defun foo (x y) (list x y))
> 
> (call-with-values #'foo 1) --> (1 nil)
> (call-with-values #'foo (values 1 2 3)) --> (1 2)
> 
> (The reason I want to do this is that I want to be write a my-maphash
> function that can map functions of either 1 or 2 arguments.)
> 
> E.

Does this help?

(defvar *fundef* (make-symbol "FUNDEF"))

(defmacro defun* (fsym lambda-list &body body)
  `(progn
     (let ((res (defun ,fsym ,lambda-list ,@body)))
       (setf (get ',fsym *fundef*) (cons ',lambda-list ',body))
       res)))

(defmacro call-with-values (fsym vexp)
  (let ((fundef (get fsym *fundef*)))
    (assert (not (null fundef)))
    `(destructuring-bind ,(car fundef) (multiple-value-list ,vexp)
       ,@(cdr fundef))))


Example:

(defun* foo (x y &rest ignore)
  (declare (ignore ignore)
  (+ x y))

(call-with-values foo (values 4 5)
=> 9

(call-with-values foo (values 4 5 6))
=> 9


Or is this too static and/or too costly?


Pascal
From: Erann Gat
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <gat-1108031555420001@k-137-79-50-101.jpl.nasa.gov>
In article <······························@news.netcologne.de>, Pascal
Costanza <········@web.de> wrote:

> In article <····················@k-137-79-50-101.jpl.nasa.gov>,
>  ···@jpl.nasa.gov (Erann Gat) wrote:
> 
> > Is there a way to achieve the following in partable CL:
> > 
> > (defmacro call-with-values (function form) ...)
> > 
> > (defun foo (x y) (list x y))
> > 
> > (call-with-values #'foo 1) --> (1 nil)
> > (call-with-values #'foo (values 1 2 3)) --> (1 2)
> > 
> > (The reason I want to do this is that I want to be write a my-maphash
> > function that can map functions of either 1 or 2 arguments.)
> > 
> > E.
> 
> Does this help?

No.


> Or is this too static and/or too costly?

Neither.  It just doesn't work.

? (call-with-values #'foo 1)
> Error: value #'FOO is not of the expected type SYMBOL.
...
? (call-with-values foo 1)
;Compiler warnings :
;   Unknown declaration (+ X Y), in an anonymous lambda form.
;   Unused lexical variable Y, in an anonymous lambda form.
;   Unused lexical variable X, in an anonymous lambda form.
> Error: Too few arguments in (1).
> While executing: #<Anonymous Function #x1588E16>
> Type Command-. to abort.
See the Restarts� menu item for further choices.
1 > 

I think what you wanted was something more like this:

(defmacro defun* (name arglist &body body)
  `(progn
     (defun ,name ,arglist ,@body)
     (setf (get ',name ':callable-with-values)
           (lambda ,(cons '&optional (append arglist '(&rest ignore)))
                  ; If you were doing this for real you'd want to be a lot
                  ; smarter about how you munged the lambda list
             (declare (ignore ignore))
             ,@body))
     ',name))

(defmacro call-with-values (symbol form)
  `(apply ,(get symbol ':callable-with-values)
          (multiple-value-list ,form)))

? (defun* foo (x y z) (list x y z))
FOO
? (call-with-values foo 1)
(1 NIL NIL)
? (call-with-values foo (values 1 2 3 4 5))
(1 2 3)

But this has the problem that it only works for functions defined with
defun*, so it doesn't work on built-in functions nor anonymous functions.

E.
From: Pascal Costanza
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <costanza-86913B.03031412082003@news.netcologne.de>
In article <····················@k-137-79-50-101.jpl.nasa.gov>,
 ···@jpl.nasa.gov (Erann Gat) wrote:

> > Or is this too static and/or too costly?
> 
> Neither.  It just doesn't work.
> 
> ? (call-with-values #'foo 1)
> > Error: value #'FOO is not of the expected type SYMBOL.

:) Well, of course I didn't expect this one to work...

> ? (call-with-values foo 1)
> ;Compiler warnings :
> ;   Unknown declaration (+ X Y), in an anonymous lambda form.
> ;   Unused lexical variable Y, in an anonymous lambda form.
> ;   Unused lexical variable X, in an anonymous lambda form.

Where do you get these warnings from? They don't appear on my machine...

> > Error: Too few arguments in (1).
> > While executing: #<Anonymous Function #x1588E16>
> > Type Command-. to abort.

Yes, that's why I have added an ignored rest parameter to my example.

> I think what you wanted was something more like this:
> 
> (defmacro defun* (name arglist &body body)
>   `(progn
>      (defun ,name ,arglist ,@body)
>      (setf (get ',name ':callable-with-values)
>            (lambda ,(cons '&optional (append arglist '(&rest ignore)))
>                   ; If you were doing this for real you'd want to be a lot
>                   ; smarter about how you munged the lambda list
>              (declare (ignore ignore))
>              ,@body))
>      ',name))
> 
> (defmacro call-with-values (symbol form)
>   `(apply ,(get symbol ':callable-with-values)
>           (multiple-value-list ,form)))

Nice - thanks for showing how the code can be improved!

> But this has the problem that it only works for functions defined with
> defun*, so it doesn't work on built-in functions nor anonymous functions.

Right. That's what I have meant with "too static" (not a very exact 
wording I have to admit).

It wosn't clear from your original posting how general this needs to be.


Pascal
From: Pascal Costanza
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <costanza-3DA447.03464612082003@news.netcologne.de>
In article <····················@k-137-79-50-101.jpl.nasa.gov>,
 ···@jpl.nasa.gov (Erann Gat) wrote:

> Is there a way to achieve the following in partable CL:
> 
> (defmacro call-with-values (function form) ...)
> 
> (defun foo (x y) (list x y))
> 
> (call-with-values #'foo 1) --> (1 nil)
> (call-with-values #'foo (values 1 2 3)) --> (1 2)
> 
> (The reason I want to do this is that I want to be write a my-maphash
> function that can map functions of either 1 or 2 arguments.)


Here's a brute force solution:

(defmacro call-with-values (fun vexp)
  (rebinding (fun)
    `(let ((vlist (multiple-value-list ,vexp)))
       (loop
         (handler-case
           (return (apply ,fun vlist))
           (error ()
                  (if vlist
                    (setf vlist (nbutlast vlist))
                    (error "too few arguments"))))))))



Pascal
From: Kaz Kylheku
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <cf333042.0308121144.6860415f@posting.google.com>
···@jpl.nasa.gov (Erann Gat) wrote in message news:<····················@k-137-79-50-101.jpl.nasa.gov>...
> Is there a way to achieve the following in partable CL:
> 
> (defmacro call-with-values (function form) ...)
> 
> (defun foo (x y) (list x y))
> 
> (call-with-values #'foo 1) --> (1 nil)
> (call-with-values #'foo (values 1 2 3)) --> (1 2)
> 
> (The reason I want to do this is that I want to be write a my-maphash
> function that can map functions of either 1 or 2 arguments.)

No can do. Function calls check errors, and so to match the correct
number of arguments, you'd have to have access to the lambda list
information.

But let's look at the bigger picture. If you don't know *how many*
arguments the target function has, how do you know anything else? The
number of arguments is just one fundamental property of the lambda
list that must be satisified for a correct function call. There are
usually others, like that some arguments must have certain types, and
satisfy various other invariants.

What you are basically asking is for a function applicator that tries
to scrape away an arbitrary subset of the possible error situations
(wrong *number* of arguments), by performing an arbitrarily chosen,
fixed transformation of the lambda list: padding with NILs or chopping
the trailing portion.

If there is a right thing to do, it's probably this: for each function
that you want to be the target of such a call, write an adapting
wrapper, or else design the function itself to be flexible enough to
take the call.

  (defun foo-wrapper (&optional (arg-1 meaningful-default-1)
                                (arg-2 meaningful-default-2))
    (foo arg-1 arg-2))

Now use the wrapper with multiple-value-call.

The wrapper not only takes care of calling the target with the right
number of parameters, but also does whatever else is needed to achieve
compatibility.

For instance, suppose that there are more arguments to the wrapper
than to the target function. Is it appropriate to reduce simply by
chopping a few trailing arguments? Maybe not; perhaps some of the
trailing arguments have to be packaged into a structure.

  (defun draw-rectangle (r)
    ...)

  (defun draw-rectangle-wrapper (x1 y1 x2 y2)
    ;; chop arguments: wrong!
    (draw-rectangle x1)
    ;; transform arguments to suitable object: right!
    (draw-rectangle (make-rectangle x1 y1 x2 y2))
From: Kent M Pitman
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <sfwwudid3ze.fsf@shell01.TheWorld.com>
···@ashi.footprints.net (Kaz Kylheku) writes:

> ···@jpl.nasa.gov (Erann Gat) wrote in message news:<····················@k-137-79-50-101.jpl.nasa.gov>...
> > Is there a way to achieve the following in partable CL:
> > 
> > (defmacro call-with-values (function form) ...)
> > 
> > (defun foo (x y) (list x y))
> > 
> > (call-with-values #'foo 1) --> (1 nil)
> > (call-with-values #'foo (values 1 2 3)) --> (1 2)
> > 
> > (The reason I want to do this is that I want to be write a my-maphash
> > function that can map functions of either 1 or 2 arguments.)
> 
> No can do. Function calls check errors, and so to match the correct
> number of arguments, you'd have to have access to the lambda list
> information.

Well, you could require it to be keyed and always use :ALLOW-OTHER-KEYS T ...
From: Joe Marshall
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <ekzoclqr.fsf@ccs.neu.edu>
···@jpl.nasa.gov (Erann Gat) writes:

> Is there a way to achieve the following in partable CL:
>
> (defmacro call-with-values (function form) ...)
>
> (defun foo (x y) (list x y))
>
> (call-with-values #'foo 1) --> (1 nil)
> (call-with-values #'foo (values 1 2 3)) --> (1 2)
>
> (The reason I want to do this is that I want to be write a my-maphash
> function that can map functions of either 1 or 2 arguments.)

Without knowing the arity of FOO, that's going to be hard.

A truly disgusting (but portable!) way of doing it would be to attempt
to invoke foo on huge argument lists and catching the `wrong number of
arguments' error...
From: Kalle Olavi Niemitalo
Subject: Re: Can call-with-values be implemented in Common Lisp?
Date: 
Message-ID: <873cg296qq.fsf@Astalo.kon.iki.fi>
Joe Marshall <···@ccs.neu.edu> writes:

> A truly disgusting (but portable!) way of doing it would be to attempt
> to invoke foo on huge argument lists and catching the `wrong number of
> arguments' error...

To be portable, that requires FOO to be defined with high safety.