Memory (let and set) in Scheme

Started by
6 comments, last by GameDev.net 17 years, 10 months ago
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, :)
Advertisement
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....
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)    ))
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...
:(

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.
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.
Quote:Original post by Anonymous Poster
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 (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.
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

This topic is closed to new replies.

Advertisement