How to reset the value of associate list element

Whatever is on your mind, whether Lisp related or not.

How to reset the value of associate list element

Postby joybee » Thu Aug 26, 2010 10:44 am

If I have a associate list ((:a a) (:b b) (:c c)), how can I set b to (:b z)?

Can you tell me different ways to do it?

Thanks!!
joybee
 
Posts: 21
Joined: Wed Jan 07, 2009 1:49 pm

Re: How to reset the value of associate list element

Postby Duke » Thu Aug 26, 2010 5:06 pm

joybee wrote:If I have a associate list ((:a a) (:b b) (:c c)), how can I set b to (:b z)?

Can you tell me different ways to do it?

Thanks!!

Not knowing the answer myself, I figured out the easy way.
Code: Select all
(let ((lst '((:a a) (:b b) (:c c))))
           (setf (car (cdr (car (cdr lst)))) 'z) ;abra-cadadr!
           lst)


I thought there was something like "getf" that could be passed as a place to setf, and which would obviate the need for the car-cdr'ing. I should check the docs.

Edit: Also, SBCL is yelling at me about "constant data" for some reason.

Edit again: This is fine, oddly enough:
Code: Select all
(let ((lst (list '(a a) '(b b) '(c c))))
           (rplacd (assoc 'b lst) 'z))

Yet the list form and the quoted form evaluate to the same thing. (Whether I use car/cdr or rplacd has no effect, incidentally.)
"If you want to improve, be content to be thought foolish and stupid." -Epictetus
Duke
 
Posts: 38
Joined: Sat Oct 17, 2009 10:40 pm

Re: How to reset the value of associate list element

Postby edgar-rft » Thu Aug 26, 2010 10:04 pm

Code: Select all
(car (cdr (car (cdr <list>)))) => (cadadr <list>)

The standard way to replace a value in an a-list is the same like Duke already had written above:

Code: Select all
(rplacd (assoc <key> <a-list>) <new-value>)

This is in so far the better solution as you normally do not know the exact position of the (key value) pair inside the a-list. 'assoc' automatically finds the right position and 'rplacd' replaces the value field.
edgar-rft
 
Posts: 154
Joined: Fri Aug 06, 2010 6:34 am
Location: Germany

Re: How to reset the value of associate list element

Postby Ramarren » Fri Aug 27, 2010 12:18 am

Duke wrote:Yet the list form and the quoted form evaluate to the same thing.


Not quite. LIST is a function which creates a list at runtime, whereas QUOTE is a special operator which creates a list at compile time. Quoted forms are treated as source literals, and modifying them has an unspecified behaviour, which in principle might include a memory protection fault if they are placed in read-only memory. I don't think any implementation actually does that, but modifying literals is usually not a good idea.
Ramarren
 
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland

Re: How to reset the value of associate list element

Postby joybee » Fri Aug 27, 2010 10:17 am

Thanks, everyone!

Here is a little example I ran on sbcl.

* (equal (list 1 2) (rplacd (list 1 1) 2))
* NIL

* (rplacd (list 1 1) 2)
* (1 . 2)

What I want is after value reset the evaluation of equal returns T. How can I achive that?
joybee
 
Posts: 21
Joined: Wed Jan 07, 2009 1:49 pm

Re: How to reset the value of associate list element

Postby Duke » Fri Aug 27, 2010 11:35 am

Ramarren wrote:Not quite. LIST is a function which creates a list at runtime, whereas QUOTE is a special operator which creates a list at compile time. Quoted forms are treated as source literals, and modifying them has an unspecified behaviour, which in principle might include a memory protection fault if they are placed in read-only memory. I don't think any implementation actually does that, but modifying literals is usually not a good idea.

I see. I guess I should have read the documentation on QUOTE while I was at it. ;)
Thanks.

joybee wrote:Thanks, everyone!

Here is a little example I ran on sbcl.

* (equal (list 1 2) (rplacd (list 1 1) 2))
* NIL

* (rplacd (list 1 1) 2)
* (1 . 2)

What I want is after value reset the evaluation of equal returns T. How can I achive that?

You notice that rplacd returns a dotted pair? That's a cons, which is distinct from a list. Putting it simply, a list is a set of conses with a NIL on the end, like this:

Code: Select all
(rplacd (list 1 1) 2) => (1 . 2)
(list 1 2) => (1 . (2 . nil))


So you see why EQUAL returns NIL in your example. Try these:

Code: Select all
(equal (cons 1 (cons 2 nil)) (list 1 2)) => T
(equal (cons 1 2) (rplacd (list 1 1) 2)) => T
"If you want to improve, be content to be thought foolish and stupid." -Epictetus
Duke
 
Posts: 38
Joined: Sat Oct 17, 2009 10:40 pm

Re: How to reset the value of associate list element

Postby Duke » Fri Aug 27, 2010 11:49 am

Duke wrote:
Ramarren wrote:Not quite. LIST is a function which creates a list at runtime, whereas QUOTE is a special operator which creates a list at compile time. Quoted forms are treated as source literals, and modifying them has an unspecified behaviour, which in principle might include a memory protection fault if they are placed in read-only memory. I don't think any implementation actually does that, but modifying literals is usually not a good idea.

I see. I guess I should have read the documentation on QUOTE while I was at it. ;)
Thanks.

joybee wrote:Thanks, everyone!

Here is a little example I ran on sbcl.

* (equal (list 1 2) (rplacd (list 1 1) 2))
* NIL

* (rplacd (list 1 1) 2)
* (1 . 2)

What I want is after value reset the evaluation of equal returns T. How can I achive that?

You notice that rplacd returns a dotted pair? That's a cons, which is distinct from a list. Putting it simply, a list is a set of conses with a NIL on the end, like this:

Code: Select all
(rplacd (list 1 1) 2) => (1 . 2)
(list 1 2) => (1 . (2 . nil))


Though it is represented as (1 2). You can see the same thing by consing together some objects with NIL:

Code: Select all
(cons 1 (cons 2 nil))


Hopefully you see why EQUAL returns NIL in your example. Try this:
Code: Select all
(equal (cons 1 2) (rplacd (list 1 1) 2)) => T
"If you want to improve, be content to be thought foolish and stupid." -Epictetus
Duke
 
Posts: 38
Joined: Sat Oct 17, 2009 10:40 pm

Re: How to reset the value of associate list element

Postby edgar-rft » Fri Aug 27, 2010 11:57 am

The particular problem here is that an association list usually is a list of dotted pairs like this:

Code: Select all
((:a . a) (:b . b) (:c . c))

This means that the last element in each cell is a symbol and not NIL, like in a normal (non-dotted) list. 'assoc' works with normal list as well as with dotted lists, but 'rplaca' expects a cons (a dotted pair) and not a normal list.

If you want to use a normal list instead of a dotted list as an association list (what is not a really good idea btw.), then there is no other way than to use 'setf' together with 'second' to replace the second element in a cell like this:

Code: Select all
(let ((lst (list (list :a 'a) (list :b 'b) (list :c 'c))))
  (setf (second (assoc :b lst)) 'z)
  lst)
=> ((:A A) (:B Z) (:C C))

But using normal lists as association list is quite non-standard Common Lisp.

You can create a dotted association list by using 'cons' like this:

Code: Select all
(list (cons :a 'a) (cons :b 'b) (cons :c 'c))
=> ((:A . A) (:B . B) (:C . C))

Now also all the code from above works:

Code: Select all
(let ((lst (list (cons :a 'a) (cons :b 'b) (cons :c 'c))))
  (rplacd (assoc :b lst) 'z)
  lst)
=> ((:A . A) (:B . Z) (:C . C))

(equal (cons 1 2) (rplacd (cons 1 1) 2))
=> T

(rplacd (cons 1 1) 2)
=> (1 . 2)
edgar-rft
 
Posts: 154
Joined: Fri Aug 06, 2010 6:34 am
Location: Germany

Re: How to reset the value of associate list element

Postby findinglisp » Sat Aug 28, 2010 7:19 am

Ramarren wrote:
Duke wrote:Yet the list form and the quoted form evaluate to the same thing.


Not quite. LIST is a function which creates a list at runtime, whereas QUOTE is a special operator which creates a list at compile time. Quoted forms are treated as source literals, and modifying them has an unspecified behaviour, which in principle might include a memory protection fault if they are placed in read-only memory. I don't think any implementation actually does that, but modifying literals is usually not a good idea.


To be a bit more specific, QUOTE is a special operator, but it merely marks the form that follows it (either an atom or a list) in the source code as being a literal, rather than a form that should be further evaluated (function, macro, or variable reference). But you can, for instance, build up a form that includes QUOTE using LIST, CONS, and other functions and then feed that to EVAL and the right things will occur. But you are correct even in that case that QUOTE marks portions of the source code sexpr as being literal values, which should not be modified because that could actually lead to modification of the source sexpr.
Cheers, Dave
Slowly but surely the world is finding Lisp. http://www.findinglisp.com/blog/
findinglisp
 
Posts: 440
Joined: Sat Jun 28, 2008 7:49 am
Location: Austin, TX

Re: How to reset the value of associate list element

Postby gugamilare » Sat Aug 28, 2010 8:01 am

Just to exemplify what findinglisp said:
Code: Select all
CL-USER> (defun literal ()
           (quote (1 2 3)))
LITERAL
CL-USER> (defun constructed ()
           (list 1 2 3))
CONSTRUCTED
CL-USER> (eq (literal) (literal))
T
CL-USER> (eq (constructed) (constructed))
NIL
CL-USER> (setf (cadr (literal)) 50)
50
CL-USER> (literal)
(1 50 3)
CL-USER> (setf (cadr (constructed)) 50)
50
CL-USER> (constructed)
(1 2 3)


You need to be careful not to modify any list created by quote, or, even better, not to create any list with quote unless you are sure it is always gonna be treated as constant data.
gugamilare
 
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil


Return to The Lounge

Who is online

Users browsing this forum: No registered users and 4 guests

cron