all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: "Pascal J. Bourguignon" <pjb@informatimago.com>
To: help-gnu-emacs@gnu.org
Subject: Re: `append' vs. `nconc'
Date: Thu, 31 Dec 2015 09:54:11 +0100	[thread overview]
Message-ID: <87mvsrc824.fsf@kuiper.lan.informatimago.com> (raw)
In-Reply-To: mailman.1406.1451546036.843.help-gnu-emacs@gnu.org

Emanuel Berg <embe8573@student.uu.se> writes:

> "Pascal J. Bourguignon" <pjb@informatimago.com>
> writes:
>
>> You must remember the literal/immutable status of
>> each item at each level.
>>
>> Since you are incapable of remembering it, you
>> should assume that the whole input data is immutable
>> and write purely functional code (ie. use append,
>> not nconc) in general.
>
> OK, so you use `nconc' when you yourself create the
> lists by hand and thus know they are not empty, all
> the while using `list' and not ', and when done you
> assign the result to a variable associated with a list
> INSTEAD of using `nconc' directly because that
> variable can hold the empty list, i.e. nil, which
> `nconc' contrary to `append' cannot handle. And you do
> this to save time!

nconc can handle nil.  But in that case, it doesn't modify it! It just
return the nconc'ed list:

(nconc nil nil (list 1 2 3) nil (list 3 4 5) nil)
--> (1 2 3 3 4 5)

(let ((list nil))
   (list (nconc list nil (list 1 2 3) nil (list 3 4 5) nil)
         list))
--> ((1 2 3 3 4 5) ; returned
     nil) ; list is still bound to nil which cannot be mutated.

(let ((list nil))
   (list (setf list (nconc list nil (list 1 2 3) nil (list 3 4 5) nil))
         list))
--> ((1 2 3 3 4 5)  ; returned and set to list
     (1 2 3 3 4 5)) ; list has been set with setf, so it's ok.

The only case where you could forget the setf, is when you just return
the nconc'ed result:

    (defun f (list to-add)
      (setf list (nconc list to-add))
      list)

can be written just:

    (defun f (list to-add)
      (nconc list to-add))

But in such a case, notice that you will have to bind or use the result
of f:

   (let ((list (list 1 2 3)))
     (setf list (f list (list 4 5 6)))
     list)
   --> (1 2 3 4 5 6)

It's like with delete, but for the opposite reason: delete cannot
transform a cons cell into the symbol nil:

    (delete 1 (list 1)) --> nil

But in anycase, it is not specified how delete (or delq) modifies the
list structure, so even:

     (let ((list (list 1 2 3 4 5)))
        (delete 3 list)
        list)

is not guaranteed to return: (1 2 4 5)

Instead, you have to write:

     (let ((list (list 1 2 3 4 5)))
        (setf list (delete 3 list))
        list)
     --> (1 2 4 5)

to ensure that list is bound to the wanted result of delete.

It is general: when you have a function that mutate a structure and
return the new structure, if the exact way how it mutates it is not
specified or if it cannot always mutate it (eg for lists, when there's
an impossible transition nil <-> cons cell), you have use the result of
the function and cannot count on the mutation.

So, to use a non-mutating function:

    (setf list (remove element list))
    (setf list (append list tail))

and to use a mutating function:

    (setf list (delete element list))
    (setf list (nconc list tail))

In both cases you must rebind the result.


> Now I got it right!

almost. ;-)

-- 
__Pascal Bourguignon__                 http://www.informatimago.com/
“The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.” -- Carl Bass CEO Autodesk


  parent reply	other threads:[~2015-12-31  8:54 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-28 16:35 Error: Setting the shell in sh-mode via a local variable does not work Johannes Kastl
2015-12-29  1:32 ` Emanuel Berg
2015-12-29 18:33   ` Johannes Kastl
2015-12-30 14:53     ` Emanuel Berg
2015-12-30 15:15       ` Robert Thorpe
2015-12-30 15:30         ` Emanuel Berg
2015-12-30 17:42         ` Johannes Kastl
2015-12-30 15:19   ` Teemu Likonen
2015-12-30 15:41     ` `append' vs. `nconc' (was: Re: Error: Setting the shell in sh-mode via a local variable does not work) Emanuel Berg
2015-12-30 16:37       ` `append' vs. `nconc' Teemu Likonen
2015-12-31  3:37         ` Emanuel Berg
     [not found]         ` <mailman.1400.1451533083.843.help-gnu-emacs@gnu.org>
2015-12-31  3:45           ` Pascal J. Bourguignon
2015-12-31  4:00             ` Emanuel Berg
2015-12-31  9:22               ` tomas
2015-12-31 18:48                 ` Emanuel Berg
     [not found]             ` <mailman.1402.1451534421.843.help-gnu-emacs@gnu.org>
2015-12-31  5:36               ` Pascal J. Bourguignon
2015-12-31  3:50         ` Emanuel Berg
     [not found]         ` <mailman.1401.1451533833.843.help-gnu-emacs@gnu.org>
2015-12-31  5:37           ` Pascal J. Bourguignon
2015-12-31  7:13             ` Emanuel Berg
2015-12-31  9:30               ` tomas
2015-12-31 17:56                 ` side effects, list sharing [was: `append' vs. `nconc'] Drew Adams
2015-12-31 19:00                   ` Emanuel Berg
2015-12-31 19:15                     ` Drew Adams
2016-01-01 13:20                       ` Emanuel Berg
2015-12-31 18:51                 ` `append' vs. `nconc' Emanuel Berg
     [not found]                 ` <mailman.1440.1451588113.843.help-gnu-emacs@gnu.org>
2016-01-01  2:53                   ` Barry Margolin
2016-01-01 13:26                     ` Emanuel Berg
     [not found]             ` <mailman.1406.1451546036.843.help-gnu-emacs@gnu.org>
2015-12-31  8:54               ` Pascal J. Bourguignon [this message]
2015-12-31  7:31           ` Teemu Likonen
2015-12-31 18:35             ` Emanuel Berg
2015-12-31 20:04               ` Teemu Likonen
2016-01-01 13:23                 ` Emanuel Berg
2016-01-01 14:02                   ` Teemu Likonen
2016-01-01 18:31                     ` Emanuel Berg
     [not found]             ` <mailman.1438.1451586967.843.help-gnu-emacs@gnu.org>
2016-01-01  6:25               ` Pascal J. Bourguignon
2016-01-01 13:31                 ` Emanuel Berg
2016-01-01 15:04                   ` Drew Adams
     [not found]     ` <mailman.1353.1451490125.843.help-gnu-emacs@gnu.org>
2015-12-30 16:18       ` Pascal J. Bourguignon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87mvsrc824.fsf@kuiper.lan.informatimago.com \
    --to=pjb@informatimago.com \
    --cc=help-gnu-emacs@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.