* Why doesn't nconc change my variable?
@ 2014-10-05 1:36 Marcin Borkowski
2014-10-05 1:58 ` Drew Adams
0 siblings, 1 reply; 13+ messages in thread
From: Marcin Borkowski @ 2014-10-05 1:36 UTC (permalink / raw)
To: help-gnu-emacs@gnu.org
Hi list,
I don't get it.
(setq my-list ())
(nconc my-list '("wtf"))
and my-list is still nil.
If, OTOH, I do
(setq my-list ())
(setq my-list (nconc my-list '("wtf")))
my-list is ("wtf").
Why is that so? I though nconc is supposed to change all its arguments
but the last one. Is the latter construct a correct way of adding an
element at the end of the list?
Best,
--
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Adam Mickiewicz University
^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: Why doesn't nconc change my variable?
2014-10-05 1:36 Marcin Borkowski
@ 2014-10-05 1:58 ` Drew Adams
2014-10-05 9:54 ` Marcin Borkowski
[not found] ` <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org>
0 siblings, 2 replies; 13+ messages in thread
From: Drew Adams @ 2014-10-05 1:58 UTC (permalink / raw)
To: Marcin Borkowski, help-gnu-emacs
> (setq my-list ())
> (nconc my-list '("wtf"))
>
> and my-list is still nil. If, OTOH, I do
> (setq my-list ())
> (setq my-list (nconc my-list '("wtf")))
>
> my-list is ("wtf").
>
> Why is that so? I though nconc is supposed to change all its
> arguments but the last one. Is the latter construct a correct
> way of adding an element at the end of the list?
No, it's not supposed to do that. You discovered just what it
does do. And you could have discovered it earlier by reading
some doc. See the Elisp manual, node `Rearrangement' (found by
doing `i nconc' in the manual).
See also node `Sets and Lists', in particular this (about `delq',
but the same idea applies to other destructive list operations):
Note that `(delq 'c sample-list)' modifies `sample-list' to splice
out the third element, but `(delq 'a sample-list)' does not splice
anything--it just returns a shorter list. Don't assume that a variable
which formerly held the argument LIST now has fewer elements, or that
it still holds the original list! Instead, save the result of `delq'
and use that. Most often we store the result back into the variable
that held the original list:
(setq flowers (delq 'rose flowers))
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable?
[not found] <mailman.10460.1412473030.1147.help-gnu-emacs@gnu.org>
@ 2014-10-05 1:59 ` Pascal J. Bourguignon
2014-10-05 9:35 ` Marcin Borkowski
[not found] ` <mailman.10474.1412501757.1147.help-gnu-emacs@gnu.org>
2014-10-05 18:04 ` Pascal J. Bourguignon
1 sibling, 2 replies; 13+ messages in thread
From: Pascal J. Bourguignon @ 2014-10-05 1:59 UTC (permalink / raw)
To: help-gnu-emacs
Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
> Hi list,
>
> I don't get it.
>
> (setq my-list ())
> (nconc my-list '("wtf"))
>
> and my-list is still nil.
>
> If, OTOH, I do
>
> (setq my-list ())
> (setq my-list (nconc my-list '("wtf")))
>
> my-list is ("wtf").
>
> Why is that so? I though nconc is supposed to change all its arguments
> but the last one. Is the latter construct a correct way of adding an
> element at the end of the list?
() is actually read as the symbol nil.
Symbols are symbols, and not cons cells.
You cannot transform a symbol into a cons cell.
It is impossible for any function to transform nil into a cons cell.
And vice-versa, it is impossible to transform a cons cell into a symbol
such as nil. This is the reason why you should also use setf when
deleting elements from a list:
(setf list (delete e list))
--
__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
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable?
2014-10-05 1:59 ` Why doesn't nconc change my variable? Pascal J. Bourguignon
@ 2014-10-05 9:35 ` Marcin Borkowski
[not found] ` <mailman.10474.1412501757.1147.help-gnu-emacs@gnu.org>
1 sibling, 0 replies; 13+ messages in thread
From: Marcin Borkowski @ 2014-10-05 9:35 UTC (permalink / raw)
To: help-gnu-emacs
On 2014-10-05, at 03:59, Pascal J. Bourguignon wrote:
> Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
>
>> Hi list,
>>
>> I don't get it.
>
> () is actually read as the symbol nil.
> Symbols are symbols, and not cons cells.
> You cannot transform a symbol into a cons cell.
> It is impossible for any function to transform nil into a cons cell.
>
> And vice-versa, it is impossible to transform a cons cell into a symbol
> such as nil. This is the reason why you should also use setf when
> deleting elements from a list:
>
> (setf list (delete e list))
I still don't understand. What if I used (list) to generate an empty
list instead of () or nil? The results seem to be still the same.
Best,
--
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Adam Mickiewicz University
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable?
2014-10-05 1:58 ` Drew Adams
@ 2014-10-05 9:54 ` Marcin Borkowski
2014-10-05 10:52 ` Thorsten Jolitz
2014-10-05 16:29 ` Drew Adams
[not found] ` <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org>
1 sibling, 2 replies; 13+ messages in thread
From: Marcin Borkowski @ 2014-10-05 9:54 UTC (permalink / raw)
To: help-gnu-emacs
On 2014-10-05, at 03:58, Drew Adams wrote:
>> (setq my-list ())
>> (nconc my-list '("wtf"))
>>
>> and my-list is still nil. If, OTOH, I do
>> (setq my-list ())
>> (setq my-list (nconc my-list '("wtf")))
>>
>> my-list is ("wtf").
>>
>> Why is that so? I though nconc is supposed to change all its
>> arguments but the last one. Is the latter construct a correct
>> way of adding an element at the end of the list?
>
> No, it's not supposed to do that. You discovered just what it
> does do. And you could have discovered it earlier by reading
> some doc. See the Elisp manual, node `Rearrangement' (found by
> doing `i nconc' in the manual).
I did read it. And a few times, for that matter.
You see, one of the worst intellectual mistakes you can make is to have
a wrong mental model of something. This seems to be the case here, and
that's why I really want to grok this issue.
> See also node `Sets and Lists', in particular this (about `delq',
> but the same idea applies to other destructive list operations):
>
> Note that `(delq 'c sample-list)' modifies `sample-list' to splice
> out the third element, but `(delq 'a sample-list)' does not splice
> anything--it just returns a shorter list. Don't assume that a variable
> which formerly held the argument LIST now has fewer elements, or that
> it still holds the original list! Instead, save the result of `delq'
> and use that. Most often we store the result back into the variable
> that held the original list:
>
> (setq flowers (delq 'rose flowers))
That I didn't read earlier; I've read it now, and still don't get it.
Sorry. (Edit: while I was writing the rest of this post, things
apparently got more clear, but I'll leave the rest, since if I'm right,
this might be (hopefully) instructive for others reading it, and I might
even want to save it to post it on my blog.)
Now I have two choices. One is to install the C source and try to read
it. This I cannot do now (time constraints, and while I did learn some
C, it was, what, fifteen years ago or so). That's why I'm asking here.
Please bear with me. This should also be good for Emacs, since it may
be the case that if I cannot understand the manual, someone else might
have troubles with that, too, so maybe the manual is buggy.
What I thought was essentially this: under the hood, a list is a pointer
(using C terminology) to a cons cell. The car of the cons cell is a
pointer to some data (say, a string), and the cdr - a pointer to the
next cons cell.
What I thought is that if you say, e.g.,
(setq my-list ("hello" "world"))
and then
(nconc my-list '("wtf"))
then my-list points to the list ("hello" "world" "wtf"). This seems to
be indeed the case. (And the wtf's get added if I repeat the nconc step
- I confirmed that experimentally.)
Now, when I say
(setq my-list (list))
(or (setq list ()))
then nconc'ing '("wtf")'s onto it (as before) does not have the same
effect.
Why on earth is that!?
Does it mean that Pascal's earlier response was right? Now that I'm
thinking about it, this makes sense: an empty list is (I would guess) a
NUL pointer, so nconc'ing has not the meaning of "changing the cdr" but
rather of "returning a brand new cons cell". This in turn means that
this sentence from the manual:
"Instead, the last CDR of each of the LISTS is changed to refer to the
following list."
is misleading: if I have an empty list, there's no cdr to change, and
that's why nconc would (probably) branch to a different subroutine and
create a brand new cons cell.
(Now that I'm wondering what the implementation might actually be, I'm
more and more tempted to look at the C source. This is probably a good
sign.)
So, now I have some more questions and one suggestion. (More knowledge
always brings more questions, right?)
1. Do I get it correctly that the "destructiveness" of some functions
(like nconc) does /not/ mean that they /change/ some of their arguments,
but only that they /may/ do it, and that relying on that is risky?
2. Do I get it correctly that what Pascal called "a nil symbol" is just
NUL under the hood? Does it mean that there's no difference between (),
nil and the result of (list) (as opposed to the results of calling list
twice with the same arguments)? (They seem to be `eq', as I've just
checked.)
3. What is the "canonical" way to append an element to a list, in the
sense that I have a variable containing (=pointing to?) a list, I want
it to point to a list one element longer? And, while at that, what is
the "canonical" way to /prepend/ an element to a list (is it `push'?)
4. (This is the suggestion.) If the above is right, could someone make
it more clear in the manual (or point me to the place in the manual
where it is actually stated)?
TIA,
--
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Adam Mickiewicz University
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable?
2014-10-05 9:54 ` Marcin Borkowski
@ 2014-10-05 10:52 ` Thorsten Jolitz
2014-10-05 16:29 ` Drew Adams
1 sibling, 0 replies; 13+ messages in thread
From: Thorsten Jolitz @ 2014-10-05 10:52 UTC (permalink / raw)
To: help-gnu-emacs
Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
>>> (setq my-list (nconc my-list '("wtf")))
> That I didn't read earlier; I've read it now, and still don't get it.
even w/o understanding the details, one can simply try to internalize
the rule that after destructive list operations a setq is necessary to
make changes take effect, i.e. always use this (pseudo-code) pattern:
,----
| (setq X (destuctively-modify X))
`----
--
cheers,
Thorsten
^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: Why doesn't nconc change my variable?
2014-10-05 9:54 ` Marcin Borkowski
2014-10-05 10:52 ` Thorsten Jolitz
@ 2014-10-05 16:29 ` Drew Adams
2014-10-05 16:38 ` Drew Adams
1 sibling, 1 reply; 13+ messages in thread
From: Drew Adams @ 2014-10-05 16:29 UTC (permalink / raw)
To: Marcin Borkowski, help-gnu-emacs
> Do I get it correctly that the "destructiveness" of some
> functions (like nconc) does /not/ mean that they /change/ some of
> their arguments, but only that they /may/ do it, and that relying
> on that is risky?
Yes. That's exactly what it means. "Destructive" operations
are _potentially_ destructive of existing data. That label is
just shorthand, to contrast with nondestructive operations that
do not modify data. It's about functions that you use for their
side effects and not just their values.
> What is the "canonical" way to append an element to a list, in
> the sense that I have a variable containing (=pointing to?) a
> list, I want it to point to a list one element longer?
There is no "canonical" way. Use `append' if you want to return
a new list that is a copy (but not a deep copy) of the original
list but with an additional element at the end.
Use `nconc' if you want to obtain a list that has the additional
element at the end, and you don't care about preserving the
original list as it was. The list you obtain _might or might
not_ share some structure with the argument lists.
A good guideline is to _not_ use "destructive" operations, in
general.
When there are use cases where you really might be able to take
advantage of them _you will know it_. Another way to put this is
that you need to really understand and be comfortable with side
effects before you try to make real use of them. Most of the
time you can (and should) avoid them (at least those that modify
list structure etc.) - and not have to worry about them.
If you do want to start experimenting with list-structure
modification then another guideline is to use "destructive"
operations only on a new list (new cons cell) that you have
assigned to only one variable. IOW, create a new list and
play with that. And do not assign any variables to any parts of
that list structure. Do not use destructive operations on an
existing list from someone else's code, or even from your code,
if you are not sure what you are doing.
Later, you might relax that second guideline: part of the point
of using list-modification operations is to _share_ list
structure (have different variables point, directly or
indirectly) to the same cons cell. But this is not something
to be trifled with. It is not easy to follow or debug program
logic when it starts fiddling with list structure and dependent
structures.
Anyway, what you are not quite understanding so far, I think,
(but you seem to be getting closer), is just what a Lisp
_variable_ is, including how it relates to its value.
1. A variable is a Lisp _symbol_ that is associated with a
value at a given moment.
2. That value could be a cons (so that the value is a non-empty
list or a dotted list).
3. A cons that might be the value of a variable has an
*independent* existence from the variable's symbol. The
symbol is mapped to its value. Function `symbol-value'
returns the value.
a. It is possible to change the value of the variable (i.e.,
change the association, so that the `symbol-value' of the
symbol points to something different.
b. It is also possible to not change that association (mapping,
binding) between symbol and cons-cell value, but to change
the car or cdr of the cons cell itself. This has the
indirect effect of changing the value: the thing that is
the value changes, instead of the variable binding changing.
4. If something changes the car or cdr of the cons cell value
of a variable, this changes the variable value. It still points
to the same cons cell, but the content of that cell is not the
same as it was.
5. A "destructive" "function" such as `nconc' _might or might not_
change a cons in one of its arguments. Typically, the function
is used for its side effects. But typically also, the _result_
returned by the function is the cons that is the main side-effect
goal. For `nconc', for example, the return value is the list
resulting from the append/concatenate operation. That returned
list (for `nconc') might or might not share structure with
one of the arguments.
6. Regardless of whether a given destructive function does in
fact change a cons in one of its arguments, it does _not_
fiddle with the mapping between any symbols and any conses.
IOW, it does not reassign or rebind any variables. Typically,
the function _sees no variables_ at all. It receives only
cons (or nil) _values_ as its arguments. It has no way of
knowing (and it does not care) about some variable that you
might have assigned or bound to one of the conses that it
looks at and might modify. That variable is your affair -
your responsibility, not the function's.
7. (Again) If you have a variable that has a value that is a cons,
and if that cons is modified, then the variable still points to
it, i.e., it points to the updated value. Modifying that cons
has the indirect side effect of modifying the variable value.
8. If you have a variable that has a value that is a cons, and if
you call a function that does _not_ modify that cons (i.e., no
modification of any part of it - e.g., any part of a cons chain
reached from its car or its cdr), then the variable value is
_not_ changed.
9. #8 includes the case where you call a "destructive" function
that might change something else (e.g. another cons cell, not
reached from the cons pointed to by the variable). The variable
value is _not_ changed.
10. #9 is relevant even if the function _returns_ a different cons,
which represents the intended _result_ of the operation. The
variable does _not_ point to this other cons. If the cons
pointed to by the variable is not, itself, changed, then the
variable value is not changed (by the operation). The variable
still points to the same cons - nothing about the function
changes what the variable points to.
11. So yes, if the _result_ returned by the operation is what
you want the variable value to be (and it typically is), then
it is up to you to reassign the variable value to it. IOW,
use `setq' to update the variable to have the new value.
HTH. Others will no doubt state all or most of this more
briefly, e.g. using some simple code examples to make it clear.
The description above is intentionally somewhat repetitive.
If it helps, fine. If not, sorry.
^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: Why doesn't nconc change my variable?
2014-10-05 16:29 ` Drew Adams
@ 2014-10-05 16:38 ` Drew Adams
0 siblings, 0 replies; 13+ messages in thread
From: Drew Adams @ 2014-10-05 16:38 UTC (permalink / raw)
To: Marcin Borkowski, help-gnu-emacs
> Later, you might relax that second guideline: part of the point
> of using list-modification operations is to _share_ list
> structure (have different variables point, directly or
> indirectly) to the same cons cell.
Sorry, those parens were misplaced. Should be this:
Later, you might relax that second guideline: part of the
point of using list-modification operations is to _share_
list structure (have different variables point, directly
or indirectly, to the same cons cell).
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable?
[not found] ` <mailman.10474.1412501757.1147.help-gnu-emacs@gnu.org>
@ 2014-10-05 17:50 ` Pascal J. Bourguignon
0 siblings, 0 replies; 13+ messages in thread
From: Pascal J. Bourguignon @ 2014-10-05 17:50 UTC (permalink / raw)
To: help-gnu-emacs
Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
> On 2014-10-05, at 03:59, Pascal J. Bourguignon wrote:
>
>> Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
>>
>>> Hi list,
>>>
>>> I don't get it.
>>
>> () is actually read as the symbol nil.
>> Symbols are symbols, and not cons cells.
>> You cannot transform a symbol into a cons cell.
>> It is impossible for any function to transform nil into a cons cell.
>>
>> And vice-versa, it is impossible to transform a cons cell into a symbol
>> such as nil. This is the reason why you should also use setf when
>> deleting elements from a list:
>>
>> (setf list (delete e list))
>
> I still don't understand. What if I used (list) to generate an empty
> list instead of () or nil? The results seem to be still the same.
The function list returns nil or a cons.
When it's given no argument, like in (list), it returns nil.
When it's given N arguments, with N>=1, then it returns N new conses,
cdr-linked, with each argument in order stored in the car slots.
So if you used (list) it would make no difference, you'd have to store
the result of delete or of nconc to the variable:
(setf list (delete 42 (list)))
(let ((list (list)))
(setf list (nconc list (list 42)))
list)
--
__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
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable?
[not found] <mailman.10460.1412473030.1147.help-gnu-emacs@gnu.org>
2014-10-05 1:59 ` Why doesn't nconc change my variable? Pascal J. Bourguignon
@ 2014-10-05 18:04 ` Pascal J. Bourguignon
1 sibling, 0 replies; 13+ messages in thread
From: Pascal J. Bourguignon @ 2014-10-05 18:04 UTC (permalink / raw)
To: help-gnu-emacs
Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
> Hi list,
>
> I don't get it.
>
> (setq my-list ())
> (nconc my-list '("wtf"))
>
> and my-list is still nil.
>
> If, OTOH, I do
>
> (setq my-list ())
> (setq my-list (nconc my-list '("wtf")))
Also, you are doing something dangerous here:
You are mixing mutable and immutable data.
This is dangerous, because now you may believe that your variable
contains mutable data, and try to mutate it, and you will actually try
to mutate immutable data, (which has usually strange or catastrophic
results).
(defvar my-list)
(setq my-list (list 1 2 3))
;; now, my-list contains mutable data. You can modify the car or
;; the cdr of any cell in the list.
(setq my-list (nconc my-list '("wtf")))
;; Now, my-list is bound to the list: (1 2 3 "wtf")
;; but this list is made of 3 mutable cons cells, and one immutable
;; cons cell, with one immutable string!
If you were to perform any of:
(setq my-list (nconc my-list '("bad")))
(setq my-list (car (last my-list) "bad"))
(setq (aref (car (last my-list)) 0) ?W)
(setq my-list (delete* "wtf" my-list :test (function string=)))
;; etc.
you would get strange/catastrophical results:
For example, try:
(defun strange (list)
(nconc list '("wtf")))
(let ((a (strange (list 1 2 3))))
(setf (car (last a)) "BAD")
(list a (strange (list 4 5 6))))
--> ((1 2 3 "BAD") (4 5 6 "BAD")) ; WTF, where is "wtf"?
If you try with:
(setf print-circle t)
(let ((a (strange (list 1 2 3))))
(setf (car (last a)) "strange")
(list a (strange (list 4 5 6))))
--> ((1 2 3 . #1=("strange")) (4 5 6 . #1#))
this may give you a hint of what's happening.
So avoid mixing mutable and immutable data, or consider the result to be
immutable (and therefore avoid using destructive operations on it).
Notice that append, while it copies the N-1 first arguments, it keeps
the last argument, so (append list '("wtf")) is no better
than (nconc list '("wtf")).
You need (nconc list (list 'wtf)) ; if you want immutable elements
or (nconc list (list (format "%s" "wtf"))) ; if you want
; mutable elements.
--
__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
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable?
[not found] ` <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org>
@ 2014-10-05 18:12 ` Pascal J. Bourguignon
2014-10-05 18:14 ` Pascal J. Bourguignon
2014-10-05 18:31 ` Pascal J. Bourguignon
2 siblings, 0 replies; 13+ messages in thread
From: Pascal J. Bourguignon @ 2014-10-05 18:12 UTC (permalink / raw)
To: help-gnu-emacs
Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
> On 2014-10-05, at 03:58, Drew Adams wrote:
>
>>> (setq my-list ())
>>> (nconc my-list '("wtf"))
>>>
>>> and my-list is still nil. If, OTOH, I do
>>> (setq my-list ())
>>> (setq my-list (nconc my-list '("wtf")))
>>>
>>> my-list is ("wtf").
>>>
>>> Why is that so? I though nconc is supposed to change all its
>>> arguments but the last one. Is the latter construct a correct
>>> way of adding an element at the end of the list?
>>
>> No, it's not supposed to do that. You discovered just what it
>> does do. And you could have discovered it earlier by reading
>> some doc. See the Elisp manual, node `Rearrangement' (found by
>> doing `i nconc' in the manual).
>
> I did read it. And a few times, for that matter.
>
> You see, one of the worst intellectual mistakes you can make is to have
> a wrong mental model of something. This seems to be the case here, and
> that's why I really want to grok this issue.
>
>> See also node `Sets and Lists', in particular this (about `delq',
>> but the same idea applies to other destructive list operations):
>>
>> Note that `(delq 'c sample-list)' modifies `sample-list' to splice
>> out the third element, but `(delq 'a sample-list)' does not splice
>> anything--it just returns a shorter list. Don't assume that a variable
>> which formerly held the argument LIST now has fewer elements, or that
>> it still holds the original list! Instead, save the result of `delq'
>> and use that. Most often we store the result back into the variable
>> that held the original list:
>>
>> (setq flowers (delq 'rose flowers))
>
> That I didn't read earlier; I've read it now, and still don't get it.
> Sorry. (Edit: while I was writing the rest of this post, things
> apparently got more clear, but I'll leave the rest, since if I'm right,
> this might be (hopefully) instructive for others reading it, and I might
> even want to save it to post it on my blog.)
>
> Now I have two choices. One is to install the C source and try to read
> it. This I cannot do now (time constraints, and while I did learn some
> C, it was, what, fifteen years ago or so). That's why I'm asking here.
> Please bear with me. This should also be good for Emacs, since it may
> be the case that if I cannot understand the manual, someone else might
> have troubles with that, too, so maybe the manual is buggy.
>
> What I thought was essentially this: under the hood, a list is a pointer
> (using C terminology) to a cons cell. The car of the cons cell is a
> pointer to some data (say, a string), and the cdr - a pointer to the
> next cons cell.
>
> What I thought is that if you say, e.g.,
>
> (setq my-list ("hello" "world"))
>
> and then
>
> (nconc my-list '("wtf"))
>
> then my-list points to the list ("hello" "world" "wtf"). This seems to
> be indeed the case. (And the wtf's get added if I repeat the nconc step
> - I confirmed that experimentally.)
You did not. Your experience was wrong or incomplete.
(setf print-circle t)
(defun strange (list) (nconc list '("wtf")))
(strange (strange (list 1 2 3)))
--> (1 2 3 . #1=("wtf" . #1#))
(setf print-circle nil
print-length 15
eval-expression-print-length 15)
(defun strange (list) (nconc list '("wtf"))) ; you need to redefine it.
(strange (strange (list 1 2 3)))
--> (1 2 3 "wtf" "wtf" "wtf" . #3)
Actually, if you try to call strange^3, it falls into an infinite loop,
because after strange^2, "wtf" is in a circular list.
Again, do not mix immutable data with mutable data, if you want to
mutate the result later!
Use: (nconc list (list "wtf")), not quote.
--
__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
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable?
[not found] ` <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org>
2014-10-05 18:12 ` Pascal J. Bourguignon
@ 2014-10-05 18:14 ` Pascal J. Bourguignon
2014-10-05 18:31 ` Pascal J. Bourguignon
2 siblings, 0 replies; 13+ messages in thread
From: Pascal J. Bourguignon @ 2014-10-05 18:14 UTC (permalink / raw)
To: help-gnu-emacs
Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
> Does it mean that Pascal's earlier response was right? Now that I'm
> thinking about it, this makes sense: an empty list is (I would guess) a
> NUL pointer,
NO! There is no pointer in lisp!
An empty list is the symbol nil!
(symbolp (list)) --> t
(consp (list)) --> nil
(symbol-name (list)) --> "nil"
(symbolp (list 1)) --> nil
(consp (list 1)) --> t
(car (list 1)) --> 1
(cdr (list 1)) --> nil
--
__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
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable?
[not found] ` <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org>
2014-10-05 18:12 ` Pascal J. Bourguignon
2014-10-05 18:14 ` Pascal J. Bourguignon
@ 2014-10-05 18:31 ` Pascal J. Bourguignon
2 siblings, 0 replies; 13+ messages in thread
From: Pascal J. Bourguignon @ 2014-10-05 18:31 UTC (permalink / raw)
To: help-gnu-emacs
Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
> (Now that I'm wondering what the implementation might actually be, I'm
> more and more tempted to look at the C source. This is probably a good
> sign.)
Instead, look at the lisp source! ;-)
(defun .nconc (&rest lists)
(let ((lists (do ((curlists lists (rest lists)))
((or (null curlists) (first curlists))
curlists))))
(when lists
(let ((current (first lists)))
(dolist (next (rest lists)
(when next
(setf (cdr (last current)) next
current next)))))))
(.nconc (list 1 2 3) (list 4 5 6) (list 7 8 9))
--> (1 2 3 4 5 6 7 8 9)
(.nconc (list 1 2 3) nil (list 4 5 6))
--> (1 2 3 4 5 6)
(.nconc (list 1 2 3) nil)
--> (1 2 3)
(.nconc nil (list 1 2 3))
--> (1 2 3)
(.nconc nil)
--> nil
> 1. Do I get it correctly that the "destructiveness" of some functions
> (like nconc) does /not/ mean that they /change/ some of their arguments,
> but only that they /may/ do it, and that relying on that is risky?
Yes.
> 2. Do I get it correctly that what Pascal called "a nil symbol" is just
> NUL under the hood?
No.
> Does it mean that there's no difference between (),
> nil and the result of (list) (as opposed to the results of calling list
> twice with the same arguments)? (They seem to be `eq', as I've just
> checked.)
If they're eq then there's no difference.
It's the lisp reader that reads () as nil:
(car (read-from-string "()")) --> nil
(car (read-from-string "nil")) --> nil
(car (read-from-string "(list)")) --> (list)
It's the lisp evaluator that calls list and have it return nil, just
like nil, since nil is bound to nil:
(symbol-value 'nil) --> nil
(eval 'nil) --> nil
(eval '(list)) --> nil
> 3. What is the "canonical" way to append an element to a list, in the
> sense that I have a variable containing (=pointing to?) a list, I want
> it to point to a list one element longer? And, while at that, what is
> the "canonical" way to /prepend/ an element to a list (is it `push'?)
(setf list (nconc list (list new-element)))
> 4. (This is the suggestion.) If the above is right, could someone make
> it more clear in the manual (or point me to the place in the manual
> where it is actually stated)?
Your above was wrong, so no. ;-)
I guess these things are explained more pedagogically in (info "(eintr)")
and notably in (info "(eintr) List Implementation")
--
__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
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2014-10-05 18:31 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <mailman.10460.1412473030.1147.help-gnu-emacs@gnu.org>
2014-10-05 1:59 ` Why doesn't nconc change my variable? Pascal J. Bourguignon
2014-10-05 9:35 ` Marcin Borkowski
[not found] ` <mailman.10474.1412501757.1147.help-gnu-emacs@gnu.org>
2014-10-05 17:50 ` Pascal J. Bourguignon
2014-10-05 18:04 ` Pascal J. Bourguignon
2014-10-05 1:36 Marcin Borkowski
2014-10-05 1:58 ` Drew Adams
2014-10-05 9:54 ` Marcin Borkowski
2014-10-05 10:52 ` Thorsten Jolitz
2014-10-05 16:29 ` Drew Adams
2014-10-05 16:38 ` Drew Adams
[not found] ` <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org>
2014-10-05 18:12 ` Pascal J. Bourguignon
2014-10-05 18:14 ` Pascal J. Bourguignon
2014-10-05 18:31 ` Pascal J. Bourguignon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).