[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

Beginner question on variable bindings

David Bradshaw

8/6/2015 1:58:00 AM


Would someone please help this newbie? I'm writing some Common Lisp to
play a game of BlackJack, and I've encountered an effect I don't
understand. The following code attempts to reduce the code down to a
minimum required to demonstrate the effect:

-------------------------------------------------------------------------------
(defvar *global-var* '( ( :lst . (1 2 3))))

;; Takes the first item from the list at :lst in the source
;; and pre-pends it to the list at :lst in the destination
(defun my-peek (source destination)
(setf (cdr(assoc :lst destination))
(cons (car(cdr(assoc :lst source))) (cdr(assoc :lst destination))))
)

;; Test run of my-peek.
(defun test-my-peek ()
(let ( (lcl '( ( :lst . (1 2 3) ) ) ))
(my-peek *global-var* lcl)
(format t "lcl=~a~%" lcl)
))
-------------------------------------------------------------------------------

The intention of my-peek is to look at the first element of a list, and
insert its value at the head of a second list (both contained within an
alist, referenced by :lst).

At the first run of test-my-peek, the code seems to work. yielding:
lcl=((LST 1 1 2 3))

However, if I run the code again in the same interactive shell, I get a
different answer:
lcl=((LST 1 1 1 2 3))

It appears that the test-my-peek function has remembered its new value
after the first call, and does not get reset by the let binding on the
second call.

Why doesn't test-my-peek give the same answer each time?

--
3 Answers

Barry Margolin

8/6/2015 2:18:00 AM

0

In article <8737zxp48r.fsf@rubybox.drb27.me>,
David Bradshaw <user@foo.bar> wrote:

> Would someone please help this newbie? I'm writing some Common Lisp to
> play a game of BlackJack, and I've encountered an effect I don't
> understand. The following code attempts to reduce the code down to a
> minimum required to demonstrate the effect:
>
> ------------------------------------------------------------------------------
> -
> (defvar *global-var* '( ( :lst . (1 2 3))))
>
> ;; Takes the first item from the list at :lst in the source
> ;; and pre-pends it to the list at :lst in the destination
> (defun my-peek (source destination)
> (setf (cdr(assoc :lst destination))
> (cons (car(cdr(assoc :lst source))) (cdr(assoc :lst destination))))
> )
>
> ;; Test run of my-peek.
> (defun test-my-peek ()
> (let ( (lcl '( ( :lst . (1 2 3) ) ) ))
> (my-peek *global-var* lcl)
> (format t "lcl=~a~%" lcl)
> ))
> ------------------------------------------------------------------------------
> -
>
> The intention of my-peek is to look at the first element of a list, and
> insert its value at the head of a second list (both contained within an
> alist, referenced by :lst).
>
> At the first run of test-my-peek, the code seems to work. yielding:
> lcl=((LST 1 1 2 3))
>
> However, if I run the code again in the same interactive shell, I get a
> different answer:
> lcl=((LST 1 1 1 2 3))
>
> It appears that the test-my-peek function has remembered its new value
> after the first call, and does not get reset by the let binding on the
> second call.
>
> Why doesn't test-my-peek give the same answer each time?

You're modifying the conses that are part of the function definition, so
that modifies the function itself.

This is why you're not supposed to use destructive functions on
literals. Change your function to:

(let ((lcl (list (cons :lst (list 1 2 3)))))
...)

and you'll get a fresh list every time you call it.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

David Bradshaw

8/6/2015 2:26:00 AM

0

Barry Margolin <barmar@alum.mit.edu> writes:

> In article <8737zxp48r.fsf@rubybox.drb27.me>,
> David Bradshaw <user@foo.bar> wrote:
>
>> Would someone please help this newbie? I'm writing some Common Lisp to
>> play a game of BlackJack, and I've encountered an effect I don't
>> understand. The following code attempts to reduce the code down to a
>> minimum required to demonstrate the effect:
>>
>> ------------------------------------------------------------------------------
>> -
>> (defvar *global-var* '( ( :lst . (1 2 3))))
>>
>> ;; Takes the first item from the list at :lst in the source
>> ;; and pre-pends it to the list at :lst in the destination
>> (defun my-peek (source destination)
>> (setf (cdr(assoc :lst destination))
>> (cons (car(cdr(assoc :lst source))) (cdr(assoc :lst destination))))
>> )
>>
>> ;; Test run of my-peek.
>> (defun test-my-peek ()
>> (let ( (lcl '( ( :lst . (1 2 3) ) ) ))
>> (my-peek *global-var* lcl)
>> (format t "lcl=~a~%" lcl)
>> ))
>> ------------------------------------------------------------------------------
>> -
>>
>> The intention of my-peek is to look at the first element of a list, and
>> insert its value at the head of a second list (both contained within an
>> alist, referenced by :lst).
>>
>> At the first run of test-my-peek, the code seems to work. yielding:
>> lcl=((LST 1 1 2 3))
>>
>> However, if I run the code again in the same interactive shell, I get a
>> different answer:
>> lcl=((LST 1 1 1 2 3))
>>
>> It appears that the test-my-peek function has remembered its new value
>> after the first call, and does not get reset by the let binding on the
>> second call.
>>
>> Why doesn't test-my-peek give the same answer each time?
>
> You're modifying the conses that are part of the function definition, so
> that modifies the function itself.
>
> This is why you're not supposed to use destructive functions on
> literals. Change your function to:
>
> (let ((lcl (list (cons :lst (list 1 2 3)))))
> ...)
>
> and you'll get a fresh list every time you call it.

That now makes perfect sense to me - and it works!
Thanks for your help.

David

--

mentificium

8/6/2015 11:24:00 AM

0

On Wednesday, August 5, 2015 at 7:18:23 PM UTC-7, Barry Margolin wrote:
> David Bradshaw <user@foo.bar> wrote: [...]

Thanks for providing the answer.

Cheers,

Arthur T. Murray/Mentifex
--
Major goal in life: Trigger a Technological Singularity;
Minor goal: Overthrow the unelected government of China;
Minor goal: Win a Nobel Prize in Physiology or Medicine;
Minor goal: [X] Reunification of East and West Germany.