From: Richard Llewellyn Smith
Subject: Novice question: decomposing a list?
Date: 
Message-ID: <1157995288.456338.164210@h48g2000cwc.googlegroups.com>
Hi

This is a simple (?) question from a Lisp beginner about decomposing
lists.

My problem concerns using lists as arguments for functions. For
example, take the expression (+ 3 2); this evaluates correctly.
However, if the arguments are stored in a list, e.g. (+ (list 3 2)),
this produces an error. I assume this is because the function expects a
list of atoms rather than an actual list data structure.

My question is, is there a simple way to either convert the list back
to its constituent elements, or tell a function to interpret a list as
its input?

Now I could use a loop of some sort to extract the elements of the list
one by one with "first", or something similarly ugly. I would have
thought though that there was a much easier way to do it though! I get
the feeling I'm missing something simple/obvious.

Thanks
Richard

From: ·············@f5.com
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <1157995603.080242.187730@i3g2000cwc.googlegroups.com>
Richard Llewellyn Smith wrote:
>
> My problem concerns using lists as arguments for functions. For
> example, take the expression (+ 3 2); this evaluates correctly.
> However, if the arguments are stored in a list, e.g. (+ (list 3 2)),
> this produces an error. I assume this is because the function expects a
> list of atoms rather than an actual list data structure.
>
> My question is, is there a simple way to either convert the list back
> to its constituent elements, or tell a function to interpret a list as
> its input?
>
> Now I could use a loop of some sort to extract the elements of the list
> one by one with "first", or something similarly ugly. I would have
> thought though that there was a much easier way to do it though! I get
> the feeling I'm missing something simple/obvious.
> 
> Thanks

(apply '+ (list 1 2 3))
From: Zach Beane
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <m3venunwfe.fsf@unnamed.xach.com>
"Richard Llewellyn Smith" <···············@gmail.com> writes:

> However, if the arguments are stored in a list, e.g. (+ (list 3 2)),
> this produces an error. 

   (apply #'+ (list 3 2)) => 5

Zach
From: Robert Uhl
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <m3k64af6px.fsf@NOSPAMgmail.com>
"Richard Llewellyn Smith" <···············@gmail.com> writes:
>
> My problem concerns using lists as arguments for functions. For
> example, take the expression (+ 3 2); this evaluates correctly.
> However, if the arguments are stored in a list, e.g. (+ (list 3 2)),
> this produces an error. I assume this is because the function expects
> a list of atoms rather than an actual list data structure.
>
> My question is, is there a simple way to either convert the list back
> to its constituent elements, or tell a function to interpret a list as
> its input?

(apply #'+ (list 3 2))

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
I won't insult your intelligence by suggesting that you really believe
what you just said.                           --William F. Buckley, Jr.
From: Pascal Bourguignon
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <878xkquutu.fsf@thalassa.informatimago.com>
"Richard Llewellyn Smith" <···············@gmail.com> writes:

> Hi
>
> This is a simple (?) question from a Lisp beginner about decomposing
> lists.
>
> My problem concerns using lists as arguments for functions. For
> example, take the expression (+ 3 2); this evaluates correctly.
> However, if the arguments are stored in a list, e.g. (+ (list 3 2)),
> this produces an error. I assume this is because the function expects a
> list of atoms rather than an actual list data structure.
>
> My question is, is there a simple way to either convert the list back
> to its constituent elements, or tell a function to interpret a list as
> its input?
>
> Now I could use a loop of some sort to extract the elements of the list
> one by one with "first", or something similarly ugly. I would have
> thought though that there was a much easier way to do it though! I get
> the feeling I'm missing something simple/obvious.

(if (<= call-argument-limits (length list))
    (reduce (function +) list)
    (apply  (function +) list))

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

This universe shipped by weight, not volume.  Some expansion may have
occurred during shipment.
From: Ari Johnson
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <m2ejui2jhm.fsf@hermes.theari.com>
Pascal Bourguignon <···@informatimago.com> writes:

> (if (<= call-argument-limits (length list))
>     (reduce (function +) list)
>     (apply  (function +) list))

I think you did that backwards.
From: Pascal Bourguignon
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <87venttzv6.fsf@thalassa.informatimago.com>
Ari Johnson <·········@gmail.com> writes:

> Pascal Bourguignon <···@informatimago.com> writes:
>
>> (if (<= call-argument-limits (length list))
>>     (reduce (function +) list)
>>     (apply  (function +) list))
>
> I think you did that backwards.

Better like that?

(if (< (length list) call-argument-limits)
    (apply  (function +) list)
    (reduce (function +) list))

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

COMPONENT EQUIVALENCY NOTICE: The subatomic particles (electrons,
protons, etc.) comprising this product are exactly the same in every
measurable respect as those used in the products of other
manufacturers, and no claim to the contrary may legitimately be
expressed or implied.
From: Ari Johnson
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <m2ac55tzd3.fsf@hermes.theari.com>
Pascal Bourguignon <···@informatimago.com> writes:

> Ari Johnson <·········@gmail.com> writes:
>
>> Pascal Bourguignon <···@informatimago.com> writes:
>>
>>> (if (<= call-argument-limits (length list))
>>>     (reduce (function +) list)
>>>     (apply  (function +) list))
>>
>> I think you did that backwards.
>
> Better like that?
>
> (if (< (length list) call-argument-limits)
>     (apply  (function +) list)
>     (reduce (function +) list))

Err...yeah.  I read it backwards.  Sorry. :)
From: choppa
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <1158098562.697477.33790@d34g2000cwd.googlegroups.com>
Pascal Bourguignon schrieb:

> Ari Johnson <·········@gmail.com> writes:
>
> > Pascal Bourguignon <···@informatimago.com> writes:
> >
> >> (if (<= call-argument-limits (length list))
> >>     (reduce (function +) list)
> >>     (apply  (function +) list))

Hi Pascal,

What is the  'call-argument-limits? My cmucl does not know the symbol.
What are the limits to prefer #'reduce over #'apply (or was I reading
backwards)?

Back to the initial question.

While #'apply and #'reduce perfectly fulfill the call of a function on
a list of parameters there is also the aspect of decomposing the list
which you mentioned and might come handy on other occations. In CL  you
have #'destructuring-bind which assigns local variables to a given list
like in

(let ((my-list '(3 4)))
  (destructuring-bind (a b) my-list
    (+ a b)))

The problem here is you need to assign as many variables as are in the
given list, otherwise you will get an error. I came on with a solution
to this for lists of arbitrary length, but it shows clearly that I have
read to many books about lisp and should start programming something
usefull :-). It is essentially the decomposition of the list by first
and rest using destructuring-bind in a nice recursive function, even
the #'cond should be an #'if.

(defun func-on-list (fun list)
  (destructuring-bind (a &rest rest)
      list
    (cond
      ((null rest) a)
      (t (funcall fun  a (func-on-list fun rest))))))
(func-on-list #'+ (list 3 4 5))

Another possibility would be to use eval and backquote notation, in
which a list can be expanded by ,@ like in

(let ((list '(1 2 3 4)))
  (eval `(+ ,@list)))

but to my understanding from the literature it is not the lisp-way to
use #'eval at run-time unless its absolutely necessary, something
similar to using functions over macros if the macro is not really
essential for the intended purpose.

Whats so bad about #'eval?

Cheers, Christoph


---------
Ups, I posted to c.l.l. :-)
From: Ari Johnson
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <m2ejugzohq.fsf@hermes.theari.com>
"choppa" <··················@t-online.de> writes:

> Whats so bad about #'eval?

EVAL is a function that takes Lisp code and evaluates it at the time
the EVAL function is called.  In interpreted code, this probably isn't
a big deal, since it will just be interpreted like everything else
that's going on.  However, in compiled code, EVAL can be implemented
in one of two ways:
 1. A full Lisp interpreter is invoked for the form to be evaluated
 2. The form is compiled at runtime and then executed

Neither one of these can be as fast as having compiled the form in
advance.
From: Bill Atkins
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <m2k648sm7f.fsf@joshu.local>
Ari Johnson <·········@gmail.com> writes:

> "choppa" <··················@t-online.de> writes:
>
>> Whats so bad about #'eval?
>
> EVAL is a function that takes Lisp code and evaluates it at the time
> the EVAL function is called.  In interpreted code, this probably isn't
> a big deal, since it will just be interpreted like everything else
> that's going on.  However, in compiled code, EVAL can be implemented
> in one of two ways:
>  1. A full Lisp interpreter is invoked for the form to be evaluated
>  2. The form is compiled at runtime and then executed
>
> Neither one of these can be as fast as having compiled the form in
> advance.

(to the OP)

Additionally, code run through EVAL can't take advantage of
lexically-scoped variables.  So:

  (let ((x 4))
    (eval 'x))

signals an error instead of evaluating to 4.  An equivalent macro
would have no problem handling this kind of thing.
From: Alberto Riva
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <ee7mj1$3806$1@usenet.osg.ufl.edu>
choppa wrote:
> Pascal Bourguignon schrieb:
> 
>> Ari Johnson <·········@gmail.com> writes:
>>
>>> Pascal Bourguignon <···@informatimago.com> writes:
>>>
>>>> (if (<= call-argument-limits (length list))
>>>>     (reduce (function +) list)
>>>>     (apply  (function +) list))
> 
> Hi Pascal,
> 
> What is the  'call-argument-limits? My cmucl does not know the symbol.

Pascal is getting things backwards today ;) Try CALL-ARGUMENTS-LIMIT. 
And then look it up in the hyperspec...

Alberto
From: Pascal Bourguignon
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <871wqgf8pf.fsf@thalassa.informatimago.com>
"choppa" <··················@t-online.de> writes:

> Pascal Bourguignon schrieb:
>
>> Ari Johnson <·········@gmail.com> writes:
>>
>> > Pascal Bourguignon <···@informatimago.com> writes:
>> >
>> >> (if (<= call-argument-limits (length list))
>> >>     (reduce (function +) list)
>> >>     (apply  (function +) list))
>
> Hi Pascal,
>
> What is the  'call-argument-limits? My cmucl does not know the symbol.
> What are the limits to prefer #'reduce over #'apply (or was I reading
> backwards)?

Sorry. I even checked the spelling in CLHS, but somehow I copied it wrongly.
It's CALL-ARGUMENTS-LIMIT.

It's the upper exclusive bound on the number of arguments that may be
passed to a  function.  So if your list has this number of elements or
more, you cannot pass it to APPLY to call the function.

Happily, it doesn't seem to apply to macros.
   (macroexpand `(some-macro . ,list))
can be run even with lists longer than call-arguments-limit.


> Back to the initial question.
>
> While #'apply and #'reduce perfectly fulfill the call of a function on
> a list of parameters there is also the aspect of decomposing the list
> which you mentioned and might come handy on other occations. In CL  you
> have #'destructuring-bind which assigns local variables to a given list
> like in
>
> (let ((my-list '(3 4)))
>   (destructuring-bind (a b) my-list
>     (+ a b)))
>
> The problem here is you need to assign as many variables as are in the
> given list, otherwise you will get an error. I came on with a solution
> to this for lists of arbitrary length, but it shows clearly that I have
> read to many books about lisp and should start programming something
> usefull :-). It is essentially the decomposition of the list by first
> and rest using destructuring-bind in a nice recursive function, even
> the #'cond should be an #'if.
>
> (defun func-on-list (fun list)
>   (destructuring-bind (a &rest rest)
>       list
>     (cond
>       ((null rest) a)
>       (t (funcall fun  a (func-on-list fun rest))))))
> (func-on-list #'+ (list 3 4 5))
>
> Another possibility would be to use eval and backquote notation, in
> which a list can be expanded by ,@ like in
>
> (let ((list '(1 2 3 4)))
>   (eval `(+ ,@list)))

This is still subject to the call-arguments-limit:

   (let ((list-of-literals (some-list-of-literals)))
      (if (<= call-arguments-limit (length list))
         (reduce (function +) list)
         (eval `(+ ,@list))))

Now the difference between eval and apply here is that with eval, each
element of the list is _evaluated_.


   (defun print-args (&rest args)
      (format t "~%My arguments are: ~{~%   ~S~}~%" args)
      args)

   (let ((list '(1 (+ 1 1) 3 (+ 2 1))))
      (values (eval  `(print-args ,@list))
              (apply 'print-args list)))

My arguments are: 
   1
   2
   3
   3

My arguments are: 
   1
   (+ 1 1)
   3
   (+ 2 1)
(1 2 3 3) ;
(1 (+ 1 1) 3 (+ 2 1))



         
> but to my understanding from the literature it is not the lisp-way to
> use #'eval at run-time unless its absolutely necessary, something
> similar to using functions over macros if the macro is not really
> essential for the intended purpose.
>
> Whats so bad about #'eval?

And to see why eval is bad, compare:

   (let ((A 2))
     (let ((list '(A 1)))
      (eval  `(+ ,@list))))


   (let ((A 2))
     (let ((list (list A 1)))
       (apply '+ list)))


-- 
__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 its wake."
From: choppa
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <1158183645.019499.236160@d34g2000cwd.googlegroups.com>
First of all thanks for the nice explanations regarding EVAL and APPLY,
they were really enlightening.

> It's CALL-ARGUMENTS-LIMIT.

I should have just looked at the CLHS and I would have found out about
the typo.

>From the example given it was not clear to me how a variable could
"know" which function is called in order to serve the right limit for
the functions arguments number ...

> It's the upper exclusive bound on the number of arguments that may be
> passed to a  function.

It turned out that I can APPLY functions to 536870911 arguments before
REDUCE is stepping in. Quite impressive !
From: Ken Tilton
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <6x%Ng.289$s11.242@newsfe11.lga>
choppa wrote:
> It turned out that I can APPLY functions to 536870911 arguments before...

"And eleven, Spock?"

Sorry, stumbled onto a Trek "classic" marathon the other night.

kt

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: choppa
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <1158221086.502804.255540@p79g2000cwp.googlegroups.com>
Ken Tilton wrote:
> choppa wrote:
> > It turned out that I can APPLY functions to 536870911 arguments before...
>
> "And eleven, Spock?"
>
> Sorry, stumbled onto a Trek "classic" marathon the other night.

:-)
From: Ari Johnson
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <m24pvb8jnw.fsf@hermes.theari.com>
"choppa" <··················@t-online.de> writes:

> First of all thanks for the nice explanations regarding EVAL and APPLY,
> they were really enlightening.
>
>> It's CALL-ARGUMENTS-LIMIT.
>
> I should have just looked at the CLHS and I would have found out about
> the typo.
>
>>From the example given it was not clear to me how a variable could
> "know" which function is called in order to serve the right limit for
> the functions arguments number ...
>
>> It's the upper exclusive bound on the number of arguments that may be
>> passed to a  function.
>
> It turned out that I can APPLY functions to 536870911 arguments before
> REDUCE is stepping in. Quite impressive !

This is not a guarantee that it is efficient to use APPLY with 536
million arguments.  Assuming that REDUCE is not implemented in a
tree-like fashion, you get:

(defun reduce (function list &rest ignored-keyword-arguments)
  (let ((result (funcall function (car list) (cadr list))))
    (loop for i in (cddr list)
      do (setf result (funcall function result i)))))

This traverses the list exactly once and calls the function (- (length
list) 1) times.  Using APPLY normally will also traverse the list once
(unless it has to reverse it for the calling conventions in play, then
twice) but will call the function only once.  However, using APPLY
results in (length list) arguments being passed (typically on the
stack other than N arguments for some N in [0,4] depending on the
implementation), and that takes up a lot of space.  Using REDUCE never
passes more than two arguments to a function, and since N in most
implementations is at least 2 the stack will never be involved for
passing arguments.

Which of these is faster?  Ask your implementation:

(let ((list (loop for i from 1 to call-arguments-limit collecting i)))
  (time (reduce #'+ list))
  (time (apply #'+ list)))

In OpenMCL neither operation takes long enough to care, since
call-arguments-limit is only 8192.  In SBCL (limiting myself to
500,000 items, since somewhere between 520,000 and 530,000 I get an
error regarding the control stack being exhausted, meaning that the
practical limit is much lower than the theoretical
call-arguments-limit ceiling and may actually vary depending on
circumstances) I get:

* (let ((list (loop for i from 1 to 500000 collecting i)))
    (time (reduce #'+ list))
    (time (apply #'+ list)))

Evaluation took:
  0.403 seconds of real time
  0.373943 seconds of user run time
  0.028996 seconds of system run time
  0 page faults and
  19,220,072 bytes consed.
Evaluation took:
  0.31 seconds of real time
  0.308953 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  15,212,176 bytes consed.

So APPLY is both time- and space-efficient compared to REDUCE.
However, REDUCE did not have a problem dealing with a list of one
million items whereas APPLY did.
From: choppa
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <1158224093.800360.41460@i3g2000cwc.googlegroups.com>
Ari Johnson wrote:

> Which of these is faster?  Ask your implementation:
>
> (let ((list (loop for i from 1 to call-arguments-limit collecting i)))
>   (time (reduce #'+ list))
>   (time (apply #'+ list)))

Well, after a lot of effort CMUCL dies as well with the words "the
party is over". So its the same here, I run out of dynamic heap space.

But thats not too bad for me, I couldn't come up with 500M catchy
argument names in the first place :-)
From: Thomas A. Russ
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <ymiejue6ykb.fsf@sevak.isi.edu>
"choppa" <··················@t-online.de> writes:

> > It's CALL-ARGUMENTS-LIMIT.
> 
> It turned out that I can APPLY functions to 536870911 arguments before
> REDUCE is stepping in. Quite impressive !

Yes, but the point of testing (and having that constant in the language)
is that the number differs between lisp implementations.  The minimum
guaranteed value is fairly small (50), so to write portable code, it is
wise to either avoid stressing this number or else to explicitly test
the values.



-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: GP lisper
Subject: Re: Novice question: decomposing a list?
Date: 
Message-ID: <slrneh44g8.9bp.spambait@phoenix.clouddancer.com>
On 11 Sep 2006 10:21:28 -0700, <···············@gmail.com> wrote:
>
> This is a simple (?) question from a Lisp beginner about decomposing
> lists.
>
> My question is, is there a simple way to either convert the list back
> to its constituent elements, or tell a function to interpret a list as
> its input?
>
> Now I could use a loop of some sort to extract the elements of the list
> one by one with "first", or something similarly ugly. I would have
> thought though that there was a much easier way to do it though! I get
> the feeling I'm missing something simple/obvious.

Looks like everybody focused on your example and missed the question
on howto to decompose a list.

Seems like you want:  destructuring-bind



-- 
Reply-To email is ignored.

-- 
Posted via a free Usenet account from http://www.teranews.com