# Memory (let and set) in Scheme

This topic is 4427 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi guys, I'm a bit confused with memory.. i've never done a memory procedure that requires a recursive tail........ So I am very confused. Basically I am creating a procedure new? with a parameter item (i.e. (define [new? item].. etc) It returns true if the item does not exist in the list. If it does, it returns false. If the item entered is equal to the string "RESET", the list holding the data (i.e. contents) becomes empty. I have created a memory thingie called contents that holds this data temporarily. My procedure new? is looking good, except the else part of the conditional expression is doomed. This is because I do not know how to go about recursion with memory. Here is my code: (define [new? value] (let [[contents empty]] (define [the-thing variable2] (cond [(empty? variable2) (begin (set! contents (cons value contents)) #t)] [(equal? (first variable2) value) #f] [(equal? value "RESET") (begin (set! contents empty) #f)] [else (the-thing (set! variable2 (rest contents)))] )) (the-thing contents) )) Please help me solve this recursion part of my expression.. i'm just not sure how to go about it. Examples on how recursion works with memory would be really good (in beginners scheme language) would be good also. Thanks for always helping me out, :)

##### Share on other sites
Your English is pretty broken, so I'm unsure of what you are trying to do. But here is my guess:

You want a procedure that closes over a value (in this case a list). This procedure, when applied to an argument, clears the list if the argument is "RESET" (and the return value is unspecified), returns true if the item does not exist in the list, and returns false if the item does exist in the list.

Here's a naive approach:

(define new?   (let ((the-list '()))    (lambda (arg)      (cond ((equal? arg "RESET") (set! the-list '()))            ((member arg the-list) #f)            (else #t)))))

Although this is my interpretation of your proposed function, it is still generally bad style. First of all, it does not clearly seperate in-band and out-of-band signals. By this, I mean that there is no way to legitimately check whether "RESET" is a member of the list this way -- "RESET" is a reserved control signal. Here is a better approach (Pardon my naming. As I said before, I am not clear on your intent):

(define new-thingie  (let ((the-list '()))    (lambda (op)      (case op        ((RESET!) (set! the-list '())        ((CONTAINS?) (lambda (arg)                        (if (member arg the-list) #t #f)))))))

This also has the advantage of allowing you to easily add additional operations. Of course, you do have an extra level of indirection, but this whole scenario seems pretty bogus.

Edit: Sorry, after having read your code, I think what you are trying to do is somewhat different from what I provided. But I hope you can figure out where you went wrong....

##### Share on other sites
I think that's what you want:
(define [new? value]  (let [[contents empty]]        (define [the-thing data-list new-value]      (cond [(empty? new-value)             (begin               (set! contents                     (cons new-value contents))               #t)]            [(equal? (first data-list)                     new-value)             #f]            [(equal? value "RESET")             (begin               (set! contents empty)               #f)]            [else             (the-thing (rest data-list) new-value)]            ))        (the-thing contents value)    ))

##### Share on other sites
That one doesn't work.

(define [new? value]
(let [[a-list empty]]
(define [accumulate value a-list]
(cond [(empty? a-list)
(begin
(set! a-list
(cons value a-list))
#t)]
[(equal? (first a-list) value)
(begin
(set! a-list
(cons value a-list))
#f)]
[(equal? value "RESET")
(set! a-list empty)]
[else
(accumulate value (rest a-list))]))
(accumulate value a-list)))

I changed it around a bit.
However, it still does not work.

Eg:
(new? "a") returns #t (WORKS SO FAR..)
(new? "a") returns #t (THUS DOESNT WORK :( )

I'm not sure how to go about it...
:(

##### Share on other sites

You should be aware that every call to new? resets the contents value, which isn't bound to anything outside the new? function anyway. It is not doing what you think it does.

Trap makes the same mistake: each call to his

(new? value)

function is equivalent to

(the-thing '() value)

Which won't get you anywhere (you want the value in contents to be preserved between calls). Where is contents bound after the new? function terminates? So Trap seems to be labouring under the same confusion you are: you'd like to do something like

(the-thing *contents* value)

where *contents* is a variable that remembers is values between calls to new?.

One way to get the semantics you want is to use a global variable.

Another way is to make a function which returns functions of the form you want. It looks like this is what you're trying to do. If you'd taken the time to understand what The Reindeer Effect wrote, you'd see he's writing a function that returns function objects. He does this because you want the 'contents' variable to persist between calls, and a way to do this is to bung it in a lexical closure (another way is to use a global variable). The contents variable must be stored somewhere if you want it to persist.

##### Share on other sites
A Here we have a solution with what (I think) are your intended semantics. As a side note, if you're unable to clearly describe your program in English, it's unlikely you can write it in scheme...

This is a function make-new which returns function objects with the desired semantics. So we bind new? to one of those function objects, and now we have a place where the contents variable is stored: in the new? closure:

(define (in-list? elem alist)  (cond ((null? alist) #f)        ((equal? elem (car alist)) #t)        (else (in-list? elem (cdr alist)))))        (define (make-new initial-value)  (let ((contents initial-value))    (lambda (value)      (cond ((eqv? value 'RESET)             (begin             (set! contents '())             "contents reset"))            ((not (in-list? value contents))             (begin             (set! contents (cons value contents))             #t))            (else #f)))))(define new? (make-new '()))

Let's see how it behaves:

> (new? "a")#t> (new? "a")#f> (new? 'RESET)"contents reset"> (new? "a")#t> (new? "a")#f

Exercise for the reader: do the same thing using a global variable instead of a closure.

##### Share on other sites
Quote:
 Original post by Anonymous PosterThis is a function make-new which returns function objects with the desired semantics. So we bind new? to one of those function objects, and now we have a place where the contents variable is stored: in the new? closure:(define (make-new initial-value)(let ((contents initial-value))(lambda (value)[...]

Sweet mother of god!
lambda after a let! Well, this is news for me, really. Never tried that construct before.[smile]
Lol, and I thought scheme would not surprise me anymore, ever.

##### Share on other sites
Heh, the lambda after the let construct is EXTREMELY useful. Scheme is lexically scoped, so the lambda (or any function definition) 'closes over' the bindings established by the let. This is what the term 'closure' means. So now you have a function object that remembers the bindings that were in place in the lexical environment in which it was created; these bindings are protected from the outside world.

This style was actually invented with Scheme, because lisps before scheme used dynamic scoping (where bindings are taken from the calling environment instead of the lexical one). It is an extremely useful and clear way to manage state. The canonical example is making a function that produces counter objects:

(define (make-counter init-value)  (let ((counter-state init-value))    (lambda ()      (begin	(display counter-state)	(set! counter-state (+ 1 counter-state))))))> (define counter1 (make-counter 0))> (define counter2 (make-counter 10))> (counter1)0> (counter1)1> (counter2)10> (counter2)11

1. 1
2. 2
Rutin
24
3. 3
4. 4
JoeJ
16
5. 5

• 14
• 29
• 11
• 11
• 9
• ### Forum Statistics

• Total Topics
631774
• Total Posts
3002274
×