From: Dr. Edmund Weitz
Subject: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <m3bshwjgkj.fsf@duke.agharta.de>
Consider this piece of code:

  (mapcar #'(lambda (x)
              (if (= x 2)
                  (values)
                  x))
          '(1 2 3))

Lispworks, CMUCL and CLISP agree on returning (1 NIL 3). However, the
CLHS entry for MAPCAR doesn't say that the function given to MAPCAR
must return a value, and it also doesn't say that NIL will be
substituted if the function doesn't return a value. Would an
implementation that returned (1 3) instead of (1 NIL 3) be conforming
or have I missed something more basic than the definition of MAPCAR in
the standard that forces CL to always return (1 NIL 3) in this case?

I think it could be convenient to be able to suppress values in such a
way but maybe you can convince me that I haven't thought deeply enough
about it.

Thanks,
Edi.

From: Kenny Tilton
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <3BFBC9BF.D725E875@nyc.rr.com>
The True Lispers will answer this better, but I do recall reading that
the receiver of (values) sees nil, ie, this is not about mapcar, this is
about (values).

I agree it would be nice to have a mapcar which tossed the nil results.
Surprised CL does not have a collect to go with mapcar. Anyway, I wrote
my own.

kenny
clinisys

"Dr. Edmund Weitz" wrote:
> 
> Consider this piece of code:
> 
>   (mapcar #'(lambda (x)
>               (if (= x 2)
>                   (values)
>                   x))
>           '(1 2 3))
> 
> Lispworks, CMUCL and CLISP agree on returning (1 NIL 3). However, the
> CLHS entry for MAPCAR doesn't say that the function given to MAPCAR
> must return a value, and it also doesn't say that NIL will be
> substituted if the function doesn't return a value. Would an
> implementation that returned (1 3) instead of (1 NIL 3) be conforming
> or have I missed something more basic than the definition of MAPCAR in
> the standard that forces CL to always return (1 NIL 3) in this case?
> 
> I think it could be convenient to be able to suppress values in such a
> way but maybe you can convince me that I haven't thought deeply enough
> about it.
> 
> Thanks,
> Edi.
From: Kent M Pitman
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <sfwg078p1d2.fsf@shell01.TheWorld.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> The True Lispers will answer this better, but I do recall reading that
> the receiver of (values) sees nil, ie, this is not about mapcar, this is
> about (values).

Right. NIL's are always filled out as additional values any time you try to use
more values than were supplied.
 (multiple-value-bind (foo bar)
     (values)
   (list foo bar))
 => (NIL NIL)

The behavior is not at all special to MAPCAR.  Lisp pads things out when
there are too few values and ignores extra values.

 (list (values) (values) (values)) => NIL NIL NIL

 (list (values 1 2 3) (values 4 5 6)) => (1 4)

> I agree it would be nice to have a mapcar which tossed the nil results.
> Surprised CL does not have a collect to go with mapcar. Anyway, I wrote
> my own.

That's what MAPCAN is for.

 (mapcan #'(lambda (x) (if (= x 2) '() (list x))) '(1 2 3)) => (1 3)

Btw, it would, IMO, not be linguistically consistent to ignore (values)
in the function given to a MAPCAR-like operation, were you to write your
own that did this, without also watching for EXTRA values from functions
that return more than one.  e.g.,

 (defun my-mapper (fn &rest lists)
   (flet ((map-fn (&rest args) 
            (declare (dynamic-extent args))
            (multiple-value-list (apply fn args))))
     (declare (dynamic-extent #'map-fn))
     (apply #'mapcan #'map-fn lists)))

 (my-mapper #'(lambda (x) (if (= x 5) (values) x))
            '(4 5 6))
 => (4 6)

 (my-mapper #'(lambda (x) (if (= x 5) (values) (truncate x 5)))
            '(4 5 6))
 => (0 4 1 1)
From: Marco Antoniotti
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <y6cvgg4ngz6.fsf@octagon.mrl.nyu.edu>
... which brings up the question that has bugged me for the pase few
days.

Why do we have MAPLIST, but not MAPSEQ

MAPSEQ <result-type> <function> &rest <sequences>

MAPSEQ is like MAP except that <function> is applied to successive
sub-sequences of the <sequences>. <function> is first applied to the
<sequences> themselves, and then to the sub-sequences of each sequence
discarding elements with index 0, then discarding elements with index
0 and 1 and so on.

E.g. (inefficient)

(defun mapseq (result-type function &rest sequences)
   (loop for i from 0 below (apply #'min 0 (mapcar #'length sequences))
         collect (apply function
                        (mapcar #'(lambda (s) (subseq s i)) sequences))
         into result
         finally (coerce result result-type)))

Cheers

-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.
From: Kent M Pitman
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <sfwherokn54.fsf@shell01.TheWorld.com>
Marco Antoniotti <·······@cs.nyu.edu> writes:

> ... which brings up the question that has bugged me for the pase few
> days.
> 
> Why do we have MAPLIST, but not MAPSEQ
> 
> MAPSEQ <result-type> <function> &rest <sequences>
> 
> MAPSEQ is like MAP except that <function> is applied to successive
> sub-sequences of the <sequences>. <function> is first applied to the
> <sequences> themselves, and then to the sub-sequences of each sequence
> discarding elements with index 0, then discarding elements with index
> 0 and 1 and so on.
> 
> E.g. (inefficient)
> 
> (defun mapseq (result-type function &rest sequences)
>    (loop for i from 0 below (apply #'min 0 (mapcar #'length sequences))
>          collect (apply function
>                         (mapcar #'(lambda (s) (subseq s i)) sequences))
>          into result
>          finally (coerce result result-type)))

Looks remarkably like MAP to me.

Are you quibbling about the name?
From: Marco Antoniotti
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <y6cwv0kkkm2.fsf@octagon.mrl.nyu.edu>
Kent M Pitman <······@world.std.com> writes:

> Marco Antoniotti <·······@cs.nyu.edu> writes:
> 
> > ... which brings up the question that has bugged me for the pase few
> > days.
> > 
> > Why do we have MAPLIST, but not MAPSEQ
> > 
> > MAPSEQ <result-type> <function> &rest <sequences>
> > 
> > MAPSEQ is like MAP except that <function> is applied to successive
> > sub-sequences of the <sequences>. <function> is first applied to the
> > <sequences> themselves, and then to the sub-sequences of each sequence
> > discarding elements with index 0, then discarding elements with index
> > 0 and 1 and so on.
> > 
> > E.g. (inefficient)
> > 
> > (defun mapseq (result-type function &rest sequences)
> >    (loop for i from 0 below (apply #'min 0 (mapcar #'length sequences))
> >          collect (apply function
> >                         (mapcar #'(lambda (s) (subseq s i)) sequences))
> >          into result
> >          finally (coerce result result-type)))
> 
> Looks remarkably like MAP to me.
> 

First of all there is a stupid error in the function. This is a better
version (tested).

(defun mapseq (result-type function &rest sequences)
  (loop with end-bound = (if sequences
			     (apply #'min (mapcar #'length sequences))
			     0)
	for i from 0 below end-bound
	collect (apply function
		       (mapcar #'(lambda (s) (subseq s i)) sequences))
	into result
	finally (return (coerce result result-type))))

The difference is

cl-prompt> (mapseq 'list #'identity "qwerty")
("qwerty" "werty" "erty" "rty" "ty" "y")

cl-prompt> (map 'list #'identity "qwerty")
(#\q #\w #\e #\r #\t #\y)

Just like

cl-prompt> (maplist #'identity '(1 2 3 4 5))
((1 2 3 4 5) (2 3 4 5) (3 4 5) (4 5) (5))

cl-prompt> (mapcar #'identity '(1 2 3 4 5))
(1 2 3 4 5)

Of course, I see where the problems are... the SUBSEQ is lurking in
the guts of the MAPSEQ function.  While one thing that could be
interesting would be to somehow get rid of it.

Maybe I would settle for a MAPSEQC (for lack of a better name): a
similar of MAPC, returning NIL.

Cheers

-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.
From: Marco Antoniotti
Subject: Sharing subsequences (Re: Must MAPCAR substitute NIL for nothing?)
Date: 
Message-ID: <y6ck7wjkj41.fsf_-_@octagon.mrl.nyu.edu>
Since we are at it.

In CMUCL

(defvar st "qwerty")
ST
* (type-of st)
(SIMPLE-BASE-STRING 6)
* (make-array 3 :displaced-to st :displaced-index-offset 1)
#(#\w #\e #\r)
* (type-of *)
(BASE-STRING 3)
* (print (make-array 3 :displaced-to st :displaced-index-offset 1))
#(#\w #\e #\r) 
#(#\w #\e #\r)
* (defvar bs #(#\w #\e #\r))
BS
* (type-of bs)
(SIMPLE-VECTOR 3)
* 

I understand the results, but I wonder whether the printed
representation of the BASE-STRING does not work.  Is this a CMUCL
quirk and/or extension?

Cheers

-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.
From: Pierre R. Mai
Subject: Re: Sharing subsequences (Re: Must MAPCAR substitute NIL for nothing?)
Date: 
Message-ID: <873d37lrb2.fsf@orion.bln.pmsf.de>
Marco Antoniotti <·······@cs.nyu.edu> writes:

<With Nitpicking Compiler Some Would Like On ;->

> In CMUCL
> 
> (defvar st "qwerty")
> ST
> * (type-of st)
> (SIMPLE-BASE-STRING 6)
> * (make-array 3 :displaced-to st :displaced-index-offset 1)

ANSI STANDARD VIOLATION:

  "[...] the consequences are undefined if the actual array element
  type of displaced-to is not type equivalent to the actual array
  element type of the array being created. [...]"

CMU CL fudges it for you, but it does it in a slightly strange way
(see below).  Generally implementations don't have to do this (and
many don't), so better write

(make-array 3 :element-type (array-element-type st) 
              :displaced-to st :displaced-index-offset 1)

> #(#\w #\e #\r)

Now it prints as "wer", just as required by the standard.

ANSI STANDARD EDUCATION PROMPT:

  "22.1.3.4 Printing Strings

  The characters of the string are output in order. If printer escaping
  is enabled, a double-quote is output before and after, and all
  double-quotes and single escapes are preceded by backslash. The
  printing of strings is not affected by *print-array*. Only the
  active elements of the string are printed. [...]"

> * (type-of *)
> (BASE-STRING 3)

Still the same.

> * (print (make-array 3 :displaced-to st :displaced-index-offset 1))
* (print (make-array 3 :element-type (array-element-type st) 
                       :displaced-to st :displaced-index-offset 1))
> #(#\w #\e #\r) 
> #(#\w #\e #\r)

"wer" 
"wer"

> * (defvar bs #(#\w #\e #\r))
> BS
> * (type-of bs)
> (SIMPLE-VECTOR 3)

* (defvar bs "wer")
BS
* (type-of bs)
(SIMPLE-BASE-STRING 3)

> I understand the results, but I wonder whether the printed
> representation of the BASE-STRING does not work.  Is this a CMUCL
> quirk and/or extension?

It seems like a bug, since the things "seem" to have the same type,
but really differ in some unknown sense.  I'll have to investigate.
That being said, had you kept to the standard, you wouldn't be in this
trouble now ;)

> Cheers

Regs, your naturally intelligent, sadistic compiler... ;)

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Pierre R. Mai
Subject: Re: Sharing subsequences (Re: Must MAPCAR substitute NIL for nothing?)
Date: 
Message-ID: <87y9kzk9el.fsf@orion.bln.pmsf.de>
"Pierre R. Mai" <····@acm.org> writes:

> It seems like a bug, since the things "seem" to have the same type,
> but really differ in some unknown sense.  I'll have to investigate.
> That being said, had you kept to the standard, you wouldn't be in this
> trouble now ;)

It was a bug, in that MAKE-ARRAY didn't error check your input enough
(ADJUST-ARRAY did).  Fix is now committed, so calling MAKE-ARRAY with
an element-type that isn't a sub-type of the element-type of the
displaced-to array will not work anymore.  So we are still more
lenient than the standard.  Maybe we shouldn't be, I haven't yet
audited the code-base enough to be certain.  This fix just brings
MAKE-ARRAY in line with ADJUST-ARRAY.

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Marco Antoniotti
Subject: Re: Sharing subsequences (Re: Must MAPCAR substitute NIL for nothing?)
Date: 
Message-ID: <y6c1yirheq2.fsf@octagon.mrl.nyu.edu>
"Pierre R. Mai" <····@acm.org> writes:

> "Pierre R. Mai" <····@acm.org> writes:
> 
> > It seems like a bug, since the things "seem" to have the same type,
> > but really differ in some unknown sense.  I'll have to investigate.
> > That being said, had you kept to the standard, you wouldn't be in this
> > trouble now ;)
> 
> It was a bug, in that MAKE-ARRAY didn't error check your input enough
> (ADJUST-ARRAY did).  Fix is now committed, so calling MAKE-ARRAY with
> an element-type that isn't a sub-type of the element-type of the
> displaced-to array will not work anymore.  So we are still more
> lenient than the standard.  Maybe we shouldn't be, I haven't yet
> audited the code-base enough to be certain.  This fix just brings
> MAKE-ARRAY in line with ADJUST-ARRAY.

Of course. Right after posting I immediately thought that
:element-type had something to do with it.

Anyway, a buglet has been fixed.  That's good.

Cheers

-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.
From: Pierre R. Mai
Subject: Re: Sharing subsequences (Re: Must MAPCAR substitute NIL for nothing?)
Date: 
Message-ID: <876683iqad.fsf@orion.bln.pmsf.de>
Marco Antoniotti <·······@cs.nyu.edu> writes:

> Of course. Right after posting I immediately thought that
> :element-type had something to do with it.
> 
> Anyway, a buglet has been fixed.  That's good.

Indeed.  Actually two have been fixed, because the tty-inspector fell
for the same mistake that you did... ;)

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Coby Beck
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <%%PK7.91750$Yb.22881086@typhoon.tampabay.rr.com>
"Dr. Edmund Weitz" <···@agharta.de> wrote in message
···················@duke.agharta.de...
> Consider this piece of code:
>
>   (mapcar #'(lambda (x)
>               (if (= x 2)
>                   (values)
>                   x))
>           '(1 2 3))
>
> Lispworks, CMUCL and CLISP agree on returning (1 NIL 3). However, the
> CLHS entry for MAPCAR doesn't say that the function given to MAPCAR
> must return a value, and it also doesn't say that NIL will be
> substituted if the function doesn't return a value. Would an
> implementation that returned (1 3) instead of (1 NIL 3) be conforming
> or have I missed something more basic than the definition of MAPCAR in
> the standard that forces CL to always return (1 NIL 3) in this case?
>

Consider:
(null (values)) => T

The point is that when a values form is in a position that needs a value
returned and none is, it will be nil instead.  Other more knowledgeable people
will probably comment more in depth on why this is/must be/should be....but
doesn't strike me as "wrong" at all, what would a sensible alternative be?

As for mapcar I think it is specified how long the list returned by mapcar is,
ie the length of the shortest list argument it was given.

Coby
--
(remove #\space "coby . beck @ opentechgroup . com")
From: Thomas F. Burdick
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <xcvk7wjvj71.fsf@conquest.OCF.Berkeley.EDU>
"Coby Beck" <·····@mercury.bc.ca> writes:

> Consider:
> (null (values)) => T
> 
> The point is that when a values form is in a position that needs a value
> returned and none is, it will be nil instead.  Other more knowledgeable people
> will probably comment more in depth on why this is/must be/should be....but
> doesn't strike me as "wrong" at all, what would a sensible alternative be?

I think a very obvious, sensible alternative would be to raise an
error.  The only way to create a form with no values is to do it
intentionally.  The current behavior and the alternative both seem
reasonable to me, but I would have no more of a problem with (null (values))
being an error, than I would with (zerop nil).  NULL is expecting a
value, and (values) is producing exactly 0 values.  And the two cases
are at least potentially distinguishable:

  * (multiple-value-call (lambda (&optional (x nil x?))
                           (declare (ignore x))
                           (if x? (princ "I got a value")
                               (princ "I got no values"))
                           (values))
      (values))
  I got no values

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Pierre R. Mai
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <877kskm6gr.fsf@orion.bln.pmsf.de>
···@agharta.de (Dr. Edmund Weitz) writes:

> Consider this piece of code:
> 
>   (mapcar #'(lambda (x)
>               (if (= x 2)
>                   (values)
>                   x))
>           '(1 2 3))
> 
> Lispworks, CMUCL and CLISP agree on returning (1 NIL 3). However, the
> CLHS entry for MAPCAR doesn't say that the function given to MAPCAR
> must return a value, and it also doesn't say that NIL will be
> substituted if the function doesn't return a value. Would an
> implementation that returned (1 3) instead of (1 NIL 3) be conforming
> or have I missed something more basic than the definition of MAPCAR in
> the standard that forces CL to always return (1 NIL 3) in this case?

You have to look not at the definition of mapcar, but at the
specification of the treatment of multiple values in the CLHS.  If a
receiving form expects more values than a "providing" form provides,
all not-provided values will be assumed to be nil.  Since normal
receiving forms (i.e. all forms that are not an instance of one of the
multiple-value-* special forms) always expect exactly one value,
providing zero values will result in nil being assumed.

Since MAPCAR doesn't specify that it expects multiple-values, we must
assume the normal single-value receiving standard, hence mapcar has to
return (1 nil 3) in your example, for any compliant implementation.

MAPCAR could have been specified differently, but that would have been
highly-unusual.  Furthermore mapcar existed before MVs were introduced
into the language, being one of the oldest "pseudo-standard"
constructs, so that changing the specification would have been
adventurous.

And using the absence of a value in this way (thereby surpressing the
nil defaulting mechanism) is highly unusual in the standard language,
and similarly in most user programs, except under special
circumstances.  This is somewhat similar to discriminating between
unsupllied and supplied default optional arguments, e.g.

(defun foo (&optional (x nil x-supplied-p))
  (if x-supplied-p
      x
      42))

(foo) => 42
(foo nil) => nil

This is sometimes desirable (e.g. make-pathname), and CL obviously
provides you with the tools to do exactly this.  But it is a feature
that does have its drawbacks, because callers that are passing through
their own defaults will have to discriminate between those situations,
too, which quickly leads to convoluted code:

(defun often-incorrect-bar (y &optional x)
  (foo y x))

(defun often-correct-bar (y &optional (x nil x-supplied-p))
  (if x-supplied-p
      (baz (foo x) y)
      (baz (foo) y)))

> I think it could be convenient to be able to suppress values in such a
> way but maybe you can convince me that I haven't thought deeply enough
> about it.

The idiom for this kind of filtering is to use MAPCAN and singleton
lists instead of MAPCAR, e.g.

(mapcan #'(lambda (x)
            (if (= x 2)
                nil
                (list x)))
        '(1 2 3))

=> (1 3)

This isn't grossly inefficient, since MAPCAR would have consed exactly
the same amount anyway.

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Dr. Edmund Weitz
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <m31yisj8n4.fsf@bird.agharta.de>
"Pierre R. Mai" <····@acm.org> writes:

> ···@agharta.de (Dr. Edmund Weitz) writes:
> 
> > Consider this piece of code:
> > 
> >   (mapcar #'(lambda (x)
> >               (if (= x 2)
> >                   (values)
> >                   x))
> >           '(1 2 3))
> > 
> > [...]
>
> The idiom for this kind of filtering is to use MAPCAN and singleton
> lists instead of MAPCAR, e.g.
> 
> (mapcan #'(lambda (x)
>             (if (= x 2)
>                 nil
>                 (list x)))
>         '(1 2 3))
> 
> => (1 3)
> 
> This isn't grossly inefficient, since MAPCAR would have consed
> exactly the same amount anyway.

Thanks to all who replied. I should have read the section about
evaluation in the CLHS before I asked.

About the MAPCAN solution above: I was aware of it but I 'felt'
(obviously without thinking enough - again) it would do unnecessary
CONSing due to the fact that it builds (LIST X) and throws the list
around X away immediately afterwards - so to say.

OK, let me try to understand this fully: (LIST X) isn't really wasted
CONSing because it results in (X . NIL) whereby no space space has to
be allocated for NIL, i.e. the CDR of this construct points to a
constant location somewhere. In the second step, MAPCAN's NCONC just
bends the CDRs of the provided lists, so that they result in one big
list - no CONS was created that wasn't used afterwards.

Is that right?

Thanks,
Edi.
From: Kent M Pitman
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <sfw3d387z17.fsf@shell01.TheWorld.com>
···@agharta.de (Dr. Edmund Weitz) writes:

> OK, let me try to understand this fully: (LIST X) isn't really wasted
> CONSing because it results in (X . NIL) whereby no space space has to
> be allocated for NIL, i.e. the CDR of this construct points to a
> constant location somewhere. In the second step, MAPCAN's NCONC just
> bends the CDRs of the provided lists, so that they result in one big
> list - no CONS was created that wasn't used afterwards.
> 
> Is that right?

Yes.
From: Jochen Schmidt
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <9tgi1n$hje$2@rznews2.rrze.uni-erlangen.de>
Dr. Edmund Weitz wrote:

> Consider this piece of code:
> 
>   (mapcar #'(lambda (x)
>               (if (= x 2)
>                   (values)
>                   x))
>           '(1 2 3))
> 
> Lispworks, CMUCL and CLISP agree on returning (1 NIL 3). However, the
> CLHS entry for MAPCAR doesn't say that the function given to MAPCAR
> must return a value, and it also doesn't say that NIL will be
> substituted if the function doesn't return a value. Would an
> implementation that returned (1 3) instead of (1 NIL 3) be conforming
> or have I missed something more basic than the definition of MAPCAR in
> the standard that forces CL to always return (1 NIL 3) in this case?
> 
> I think it could be convenient to be able to suppress values in such a
> way but maybe you can convince me that I haven't thought deeply enough
> about it.

What about

(mapcan #'(lambda (x) (unless (= x 2) (list x)) '(1 2 3))
==> (1 3)

ciao,
Jochen

--
http://www.dataheaven.de
From: Jochen Schmidt
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <9tgj4s$i9r$1@rznews2.rrze.uni-erlangen.de>
Jochen Schmidt wrote:

> Dr. Edmund Weitz wrote:
> 
>> Consider this piece of code:
>> 
>>   (mapcar #'(lambda (x)
>>               (if (= x 2)
>>                   (values)
>>                   x))
>>           '(1 2 3))
>> 
>> Lispworks, CMUCL and CLISP agree on returning (1 NIL 3). However, the
>> CLHS entry for MAPCAR doesn't say that the function given to MAPCAR
>> must return a value, and it also doesn't say that NIL will be
>> substituted if the function doesn't return a value. Would an
>> implementation that returned (1 3) instead of (1 NIL 3) be conforming
>> or have I missed something more basic than the definition of MAPCAR in
>> the standard that forces CL to always return (1 NIL 3) in this case?
>> 
>> I think it could be convenient to be able to suppress values in such a
>> way but maybe you can convince me that I haven't thought deeply enough
>> about it.
> 
> What about
> 
> (mapcan #'(lambda (x) (unless (= x 2) (list x)) '(1 2 3))
> ==> (1 3)

Or if you want it a bit more similar to MAPCAR

(defun mapfilter (fn list)
  (mapcan #'(lambda (x) (when (funcall fn) (list x))) list))

(mapfilter #'(lambda (x)
               (if (= x 2)
                  (values)
                  x))
    '(1 2 3))

Which is besides of the name exactly what you wanted MAPCAR to do (If I 
have understood you right).

For you _concrete_ example something like (remove 2 '(1 2 3)) might have 
been a better idea - but I think the idea was to combine mapping with such 
filtering.

ciao,
Jochen

--
http://www.dataheaven.de
From: Jochen Schmidt
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <9tgk4b$iq4$1@rznews2.rrze.uni-erlangen.de>
Jochen Schmidt wrote:

> Jochen Schmidt wrote:
> 
>> Dr. Edmund Weitz wrote:
>> 
>>> Consider this piece of code:
>>> 
>>>   (mapcar #'(lambda (x)
>>>               (if (= x 2)
>>>                   (values)
>>>                   x))
>>>           '(1 2 3))
>>> 
>>> Lispworks, CMUCL and CLISP agree on returning (1 NIL 3). However, the
>>> CLHS entry for MAPCAR doesn't say that the function given to MAPCAR
>>> must return a value, and it also doesn't say that NIL will be
>>> substituted if the function doesn't return a value. Would an
>>> implementation that returned (1 3) instead of (1 NIL 3) be conforming
>>> or have I missed something more basic than the definition of MAPCAR in
>>> the standard that forces CL to always return (1 NIL 3) in this case?
>>> 
>>> I think it could be convenient to be able to suppress values in such a
>>> way but maybe you can convince me that I haven't thought deeply enough
>>> about it.
>> 
>> What about
>> 
>> (mapcan #'(lambda (x) (unless (= x 2) (list x)) '(1 2 3))
>> ==> (1 3)
> 
> Or if you want it a bit more similar to MAPCAR
> 
> (defun mapfilter (fn list)
>   (mapcan #'(lambda (x) (when (funcall fn) (list x))) list))

Sorry for that but - I did not test it.

(defun mapfilter (fn list)
  (mapcan #'(lambda (x) (when (funcall fn x) (list x))) list))

Extending it to multiple argument list is left as an excercise to the 
reader ;-)

--
http://www.dataheaven.de
From: Erik Naggum
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <3215360490307858@naggum.net>
* Dr. Edmund Weitz
| have I missed something more basic than the definition of MAPCAR in
| the standard that forces CL to always return (1 NIL 3) in this case?

  Yes.  The primary value of (values) is nil.

| I think it could be convenient to be able to suppress values in such a
| way but maybe you can convince me that I haven't thought deeply enough
| about it.

  Use mapcan and return lists of varying lengths.

///
-- 
  Norway is now run by a priest from the fundamentalist Christian People's
  Party, the fifth largest party representing one eighth of the electorate.
-- 
  Carrying a Swiss Army pocket knife in Oslo, Norway, is a criminal offense.
From: Bruce Hoult
Subject: Re: Must MAPCAR substitute NIL for nothing?
Date: 
Message-ID: <bruce-441E2E.14514522112001@news.paradise.net.nz>
In article <··············@duke.agharta.de>, ···@agharta.de (Dr. Edmund 
Weitz) wrote:

> Consider this piece of code:
> 
>   (mapcar #'(lambda (x)
>               (if (= x 2)
>                   (values)
>                   x))
>           '(1 2 3))
> 
> Lispworks, CMUCL and CLISP agree on returning (1 NIL 3).

Don't know about CL, but here's the Dylan perspective:

if you write...

   let (x, y, z) = foo();

... then x, y, and z are bound to the results of foo().  If foo() 
returns more than three results then the extra ones are discarded.  If 
foo() returns fewer then three results then the extra variables are 
bound to #f.

Obviously a special case of this is...

   let x = values();

... in which case x will be bound to #f.



The same applies to, say, a function argument supplied with zero values 
or more than 1 value.  If zero, then #f is used, if too many then the 
extra are discarded.


The Dylan Reference Manual, at...

  http://www.gwydiondylan.org/drm/drm_102.html#HEADING102-524

... says that "The new collection is created by calling _make_ on that 
type, with a size: initiazation argument whose value is the number of 
corresponding elements in the collections".

Thus the result from map() can have neither more nor fewer elements than 
the number of elements in the source collections.


You could write your own version of map() which bound the results from 
the function using "let (#rest results) = func()", and then appended 
them to the destimation collection, but that's not the standard "map".

-- Bruce