Here is some code on deleting an item in a queue. I don't understand why the last word, queue is there. I am sure Im missing something simple - Could someone please clarify?
(define (delete-queue! queue)
(cond ((empty-queue? queue)
(error "DELETE! called with an empty queue" queue))
(else
(set-front-ptr! queue (cdr (front-ptr queue)))
queue)))
^ This last line is where my question is; why is queue there? As long as the front-ptr is set to the cdr of the front-ptr, isn't that all that's needed for the exclusion of the first element in the queue?
Here are definition of some of the functions defined above:
(define (front-ptr queue) (car queue))
(define (rear-ptr queue) (cdr queue))
(define (set-front-ptr! queue item) (set-car! queue item))
(define (set-rear-ptr! queue item) (set-cdr! queue item))
It makes the function return the queue. It doesn't look like it's needed for removing the first item, no. Maybe it's handy for the code that calls the function.
Related
I'm currently learning to use some slightly more advanced features of scheme, and I've hit a road-block with lazy lists.
Basically, I'm trying to create an infinite, lazily generated list, and apply a lazy filter on it, and only take a single element. My hope was that this would consume very little memory: the filter looks at only one element at a time, and there's no need to store the previous entries. Here is my attempt at this:
(define lazy-inf-seq
(lambda (start next)
(delay (cons start (lazy-inf-seq (next start) next)))))
(define lazy-arithmetic-sequence
(lambda (start d)
(lazy-inf-seq start (lambda (v) (+ v d)))))
(define lazy-filter
(lambda (pred seq)
(delay
(let loop ([sequence seq])
(let ([forced (force sequence)])
(cond [(null? forced) '()]
[(pred (car forced))
(cons (car forced) (lazy-filter pred (cdr forced)))]
[else (loop (cdr forced))]))))))
So, to be clear, a "lazy list" here is a procedure that, when (force)d, produces (head . tail), where head is one of the values on the list, and tail is the rest of the list (that needs to be forced in turn). I don't know if this is a "standard" lazy list in scheme or whatever, but it was the variant that made the most sense to me.
The (lazy-arithmetic-sequence a b) function produces (lazily) the infinite list a, a+b, a+2b, a+3b, ...
The lazy-filter function is the heart of the matter: it takes a predicate and a lazy list, and returns a lazy list with all the filtered elements. When forced, it goes through the input list finding the first element that should be included, and then returns that element consed with the lazy-filter of the rest of the list.
To test this out, I run this line:
(force (lazy-filter (lambda (v) (= v 1000000000)) (lazy-arithmetic-sequence 0 1)))
This is of course a rather pointless filter ("find the element with value one billion in this list from 0 to infinity"), but the point is to test the code out. The problem is that this consumes crazy amounts of memory. Within seconds its up to many gigabytes, and it shows no signs of slowing down, and I don't understand why.
I don't understand why the garbage collector doesn't reclaim the memory produced from the list. The loop in lazy-filter is tail-recursive, and there's no other references to the lazy list, so I feel like the GC should just gobble all that memory up. To make sure I even made a version that ran the garbage collector every iteration of the lazy-filter loop, and of course it didn't help.
My suspicion is that there's some reference hanging on to the head of the list that I'm not seeing. Like, the closure created by the delay in lazy-filter is somehow making the seq reference hang around, or something.
How can I rewrite this to not consume infinite amounts of memory?
I'm running Chez Scheme if that makes any difference, but I suspect that the problem is with me rather than the scheme implementation 🙂
Here's how to fix your problem:
(define lazy-filter
(lambda (pred seq)
(delay
(let loop ([sequence seq])
;; the following single line is added: ------ NB!
(set! seq sequence)
(let ([forced (force sequence)])
(cond [(null? forced) '()]
[(pred (car forced))
(cons (car forced) (lazy-filter pred (cdr forced)))]
[else (loop (cdr forced))]))))))
I tried (force (lazy-filter (lambda (v) (= v 100000000)) (lazy-arithmetic-sequence 0 1))) in Racket, and it finishes up, though slowly, running in constant memory as reported by my OS, returning
'(100000000 . #<promise:unsaved-editor:12:4>)
Without the (set! seq sequence) the memory consumption reported by OS shots up by several gigabytes and then Racket reports it has run out of memory and the execution is aborted.
Some other re-writes of your code are found below, as are previous versions of this answer.
Trying your code in Racket's debugger, we get
forced and sequence are advancing along nicely, but seq is still at the start. And no wonder, nothing is changing it.
That's exactly what you suspected. A reference to the start of the sequence can not be released because seq is holding on to it until the result is found and returned (as the cons pair). For 100 elements it's not an issue, but for 1 billion it surely is.
Float loop up and out of lazy-filter and the problem seems to be gone:
This code transformation technique is known as lambda lifting.
The call to loop in lazy-filter becomes fully and manifestly tail because of it. Thanks to the tail call optimization the new call frame (for loop) can replace the old (for lazy-filter), which can now be discarded, together with its references into any data it held (here, seq).
The debugger snapshots show what's going on when the code is being debugged. Maybe without the debugging it is compiled differently, more efficiently. Maybe A Very Smart Compiler would in effect compile it by lambda lifting so the reference to seq could be relinquished, in the first code variant just as it is in the second. Looks like your Chez Scheme though compiles it just like Racket with debugging does (note, my version of Racket is old).
So it does seem like an implementation issue.
You will know for sure if you try the lambda-lifted code and see whether this fixes the problem:
(define (lazy-filter pred seq)
(delay (lazy-filter-loop pred seq)))
(define (lazy-filter-loop pred sequence)
(let ([forced (force sequence)])
(cond [(null? forced) '()]
[(pred (car forced))
(cons (car forced)
(lazy-filter pred (cdr forced)))]
[else (lazy-filter-loop pred (cdr forced))])))
Although one could reasonably expect of Chez compiler to do this on its own. Maybe you are running interpreted code? Maybe you have the debugging information included? These are the questions to consider.
Another way to restructure your code is
(define lazy-filter
(lambda (pred seq)
(delay
(let loop ([forced (force seq)])
(cond [(null? forced) '()]
[(pred (car forced))
(cons (car forced)
(lazy-filter pred (cdr forced)))]
[else (set! seq (cdr forced))
(loop (force (cdr forced)))])))))
(the older version of the answer follows:)
Let's see what forcing your expressions entails. I will use shorter names for your variables and functions, for more visual and immediate reading of the code.
We'll use SSA program transformation to make a function's operational meaning explicit, and stop only on encountering a delay form.
You don't include your delay and force definitions, but we'll assume that (force (delay <exp>)) = <exp>:
(define (lz-seq s n) (delay (cons s (lz-seq (n s) n))))
(force (lz-seq s n))
=
(cons s (lz-seq (n s) n)) ;; lz-seq is a function, needs its args eval'd
=
(cons s (let* ([s2 (n s)]) (lz-seq s2 n)))
=
(let* ([s2 (n s)]
[lz2 (delay (cons s2 (lz-seq (n s2) n))) ])
(cons s lz2))
We've discovered that forcing your kind of lazy sequence forces its second element as well as the first!
(the following is incorrect:)
And this in fact exactly explains the behavior you're observing:
(force (lazy-filter (lambda (v) (= v 1000000000)) (lazy-arithmetic-sequence 0 1)))
needs to find out the second element of the filtered infinite stream before it can return the first cons cell of the result, but there's only one element in the filtered sequence, so the search for the second one never ends.
I am writing some code for a roster management program in scheme, but encounter an issue when I try to add a student. I am using a roster parameter which is a list of lists, each sublist being a student's record. The first student I add works without issue, however when I attempt to add a second student, I receive one of two instances of the same error.
If I try to enter a student who should be added, I get the error :
The object ("21" "Anon Ymous" "89") is not applicable.
If the student I add has information that conflicts with the existing student, I get the error :
The object (("23" "Anon Ymous" "11")) is not applicable.
The code for this section is as follows :
(define addifnotcontains
(lambda (roster item)
(cond ((null? roster) (list item))
((equal? (car (car roster)) (car item))
(begin
(display "\tID Already Exists\n")
(roster)
))
((equal? (cadr (car roster)) (cadr item))
(begin
(display "\tName Already Exists\n")
(roster)
))
(else (cons ((car roster) addifnotcontains (cdr roster))))
)
)
)
and the call for this function is (menu (addifnotcontains roster (buildobject 0 '()))) where menu is a lambda function that simply takes in a roster
I know that this issue has been caused by mismatched or misplaced parentheses in my code previously, but I cannot tell why it is occurring this time. I suspect it has something to do with calling (roster) at the end of the begin block, but as I understand it, the begin block returns the last value called within the block. What am I doing wrong?
In the first case, you're trying to apply (car roster) to addifnotcontains and (cdr roster):
(cons ((car roster) addifnotcontains (cdr roster)))
^ <-- This is one expression --> ^
You're also only passing one argument to cons and forgetting to pass along item.
This should be
(cons (car roster) (addifnotcontains (cdr roster) item))
In the second case, you're trying to apply roster as a function.
You're correct in that the value of a begin block is the value of the last expression in the block, but in your case this expression should be roster, not (roster).
(Remember that you can't add parentheses willy-nilly in Scheme like you can in some other languages; parentheses are always significant.)
In a Computer Science course I am taking, for homework, we were tasked with several different questions all pertaining to message passing. I have been able to solve all but one, which asks for the following:
Write a mailman object factory (make-mailman) that takes in no parameters and
returns a message-passing object that responds to the following messages:
'add-to-route: return a procedure that takes in an arbitrary number of mailbox objects
and adds them to the mailman object's “route”
'collect-letters: return a procedure that takes in an arbitrary number of letter objects and
collects them for future distribution
'distribute: add each of the collected letters to the mailbox on the mailman's route whose
address matches the letter's destination and return a list of any letters whose destinations
did not match any mailboxes on the route (Note: After each passing of
'distribute
the
mailman object should have no collected letters.)
Some remarks that are given to make the code easier include:
If multiple letters are distributed to the same mailbox in one distribution round, any one
of them may be the “latest” letter whose message is returned by passing 'get-latest-message
to the mailbox.
No two mailboxes will have the same address.
No mailbox or letter will be passed to the mailman more than once.
The bad letters returned by distribute do not need to be in a specific order.
Use the . args syntax for accepting arbitrary amount of arguments.
This is what I have been able to figure out for myself:
(define (make-mailman)
(let ((T '()))
(define (route-adder . mobjects)
(assoc mobjects T))
(define (letter-collecter . lobjects)
(assoc lobjects T))
(define (add-to-route mobjects)
(begin (set! T (cons (route-adder . mobjects) T)) 'done))
(define (collect-letters lobjects)
(begin (set! T (cons (sort-strings (letter-collecter . lobjects)) T)) 'done))
(define (dispatch z)
(cond ((eq? z 'add-to-route) add-to-route)
((eq? z 'collect-letters) collect-letters)
((eq? z 'distribute) "unsure of what to do here")
(else "Invalid option")))
dispatch))
Any help that can be given to me here will be appreciated, as I have tried looking at this problem for a while, and cannot figure out what to do from here.
Your code has all kinds of mix-ups. :) Let's proceed step by step.
The dispatch bit is almost OK:
(define (make-mailman)
(let ...
...
(define (dispatch msg) ;; use short but suggestive var names
(cond
((eq? msg 'add-to-route) add-to-route)
((eq? msg 'collect-letters) collect-letters)
((eq? msg 'distribute)
;; "unsure of what to do here" <<-- Distribute the letters, what else?
distribute-the-letters)
(else "Invalid option")))
dispatch))
With such objects, a sample call will be (define ob (make-mailman)) and then ((ob 'add-to-route) box1 box2 ... boxn) etc. So add-to-route procedure must be defined this way:
(define (make-mailman)
(let ((self (list '(ROUTE) ; each mailman has a route, and a mailbag
'(MAILBAG)))) ; use suggestive name here (T, what T?)
...
(define (add-to-route . mailboxes)
(let ((route (assoc 'ROUTE self)))
(set-cdr! route
(append mailboxes ; there will be no duplicates
(cdr route)))
'DONE))
Right? Same with the letters:
(define (collect-letters . letters)
(let ((mailbag (assoc 'MAILBAG self)))
.....
'DONE))
Now we can deal with the missing part, distribute-the-letters:
(define (distribute-the-letters)
;; for each letter in my mailbag
(let* ((mailbag (assoc 'MAILBAG self))
(mailboxes (cdr (assoc 'ROUTE self)))
(letters (cdr mailbag)))
(if (null? letters) ()
(let loop ((letter (car letters))
(letters (cdr letters))
(not-delivered ()))
;; access its address,
(let* ((address (letter 'get-address))
;; (we assume it supports this interface,
;; or maybe that's part of a previous assignment)
;; and find a mailbox on my route such that
(mbx (find-mailbox address mailboxes)))
;; its address matches the letter's
;; and if so,
(if .....
;; put that letter into this mailbox:
((mbx 'put-letter) letter)
;; (we assume it supports this interface,
;; or maybe that's part of a previous assignment)
;; but if not, add letter to the "not-delivered" list
..... )
(if (null? letters)
;; having emptied the mailbag, return the "not-delivered" list
(begin (set-cdr! mailbag nil) not-delivered)
(loop (car letters) (cdr letters) not-delivered)))))))
We assume that both letter and mailbox objects support the message type 'get-address to which they both return the same comparable address type of object, and that mailbox objects support 'put-letter message.
Other than the specifics of the message functionality, it looks like you've nailed it. There are however some errors:
This (route-adder . mobjects) should be (router-adder objects) and similarly for (letter-collector . lobjects).
The use of begin is unneeded. The body of a (define (func . args) <body> ...) is implicitly enclosed in a begin.
Idiomatically your code could be written as:
(define (make-mailman)
(let ((T '()))
;; ...
(lambda (z)
(case z
((add-to-route) add-to-route)
((collect-letters) collect-letters)
((distribute) distribute)
(else (error "Invalid option"))))))
[but you may not know about case nor lambda yet...]
As for solving the actual messaging functionality. You are going to need to maintain a set of mailboxes where each mailbox is going to hold a set of letters. A letter will presumably consist of an address and some content (extra credit for a return-address). The distribute behavior will check the address on each letter and deposit it in its mailbox. The mailman will need to hold letters (while on his route collecting-letters) until instructed to distribute.
For this you might start by building up the lower-levels of the functionality and then using the lower-levels to build up the actual message passing functionality. Starting like, for example:
(define (make-letter addr content)
`(LETTER ,addr ,content))
(define letter-addr cadr)
;; ...
(define (make-mailbox addr)
'(MBOX ,addr))
(define mailbox-letters cddr)
(define (mailbox-letters-add mailbox letter)
(set-cdr! (cdr mailbox) (cons letter (mailbox-letters mailbox))))
;;...
At the moment, as part of an assignment, I am attempting to write a scheme program that accepts 3 messages, 'get-student-average 'get-assignment-average and 'add-grade, and returns the information as necessary. 'add-grade basically gives the student id, assignment, and grade as it is inserted in that order. I am still working on the student and assignment average messages (hence the semicolons in front of them), but what keeps failing when I try to run it is the 'add-grade message. It keeps saying that grades is an unbound variable. This is the code that I am testing it with:
(define (make-grades)
(define T '())
(define (dispatch op)
((eq? op 'add-grade) (lambda(id as gr) (set! T (append T (list (list id as gr)
)))))
;((eq? op 'get-student-average) (lambda(x) ( )))
;((eq? op 'get-assignment-average)
))
(define grades (make-grades))
((grades 'add-grade) 7 1 85))
I'm not sure what it is that I am doing wrong to try and get back the information with that. I thought that, as with tables in scheme, the trick is in appending the list as a list to a null value, then setting it.
There are a bunch of other test cases (including some for the 'average messages), but I did not include them as I feel that it's just repeating more of the same. The one other thing I feel I should mention is that all of the test-cases are held together within a list, starting with '( and ending with ).
There are a couple of problems with your code. For starters, you are not actually checking what message is being received (there should be a cond or a series of nested ifs or a case somewhere). And you're not returning the dispatcher procedure. Here, try this to get started:
(define (make-grades)
(define T '())
(define (dispatch op)
(cond ((eq? op 'add-grade)
(lambda (id as gr)
(set! T (append T (list (list id as gr))))))
;((eq? op 'get-student-average) (lambda(x) ( )))
;((eq? op 'get-assignment-average)
))
dispatch)
Also, you should add a fourth message to return the list, for testing purposes.
Someone tell me what is wrong with this code. I thought I mastered a few scheme skills to solve a friend's problem but it ended up messing my head. I am trying to remove all similar elements off the list. Earlier it was removing only the first element I want to remove, but now its removing the car and the first element f what I want to remove. I am looking for an output like: (delete 3 (list 2 3 4 3 5 3)), returns (2 4 5).
(define (delete n lst)
(cond
((null? lst) null)
((equal? n (car lst)) (cdr lst))
(else
(remove n (cdr lst)))))
It's because of this conditional:
((equal? n (car lst)) (cdr lst))
What this line does is it checks that n is the same as the first element in the list. If it is, it returns the rest of the list. Since your target element is the second element of the list, it returns the rest of the list, from the third element onward. Your first element in the list is completely dropped. You're not keeping track of the OK elements you've checked so far.
From your code, it looks like you want to loop through the elements of the list and, if you find your target value, call remove. If you want to implement it in this fashion, you need to also track the values that you've checked and verified that are not your target value. So your function needs to take three parameters: n, your target; lst the remaining numbers to check; and clean (or whatever you want to call it) that holds the already checked numbers.
This is a working version of your algorithm:
(define (delete n lst clean)
(cond
((empty? lst) clean)
((equal? n (car lst)) (delete n (cdr lst) clean))
(else
(delete n (cdr lst) (append clean (list (car lst)))))))
You'd call it like so: (delete 3 (list 2 3 4 3 5 3) '())
First it checks if you have numbers left to check. If you don't, it returns your clean list.
Then it checks to see if the first element matches your target element. If it does, then it calls delete again, effectively dropping the first element in the lst (notice it does not append it to the list of clean numbers).
The else, which is reached if the first element is not the target number, appends the first value of lst to the end of clean and calls delete again.
(Note that this code uses tail recursion, which is a way of writing recursive methods that track the intermediate values with each recursive call, as opposed to "regular" recursion that does the calculation at the end. Samrat's answer, below, is a regular recursive solution. A discussion of the tail recursion can be found here.)
From your post, it sounds like you want to remove all instances of the target number. Instead of using the remove function -- which only removes the first instance of the target number -- you should look at using the remove* function, which removes all instances. This would greatly simplify your function. So to remove all instances of 3 from your list, this would suffice:
(remove* '(3) (list 2 3 4 3 5 3))
If you wanted to wrap it in a function:
(define (delete n lst)
(remove* (list n) lst))
You should read up on map functions in general, since they pretty much do what you're looking for. (They apply a procedure against all elements in a list; The above could also be implemented with a filter-map if you had a more complicated procedure.)
Here's what I came up with:
(define (delete n lst)
(cond ((empty? lst) lst)
((= (car lst) n) (delete n (cdr lst)))
(else (append (list (car lst)) (delete n (cdr lst))))))