Shorest-Seek-Time in Scheme - scheme

So currently I'm working on a problem of implementing the shortest-seek-time disk scheduling algorithm. Our task is, being passed a list of tracks, to return a list of length 3 containing the Avg Movement, Total movement, and then a list of the movement amounts. Currently I'm tackling returning the list of movements as I feel the total and avg's are trivial.
What I'm currently stuck on is saving the distance between the current head position and the current track so I can continue searching the list for the shortest seek time. What I did first was to sort the list and pass it into a separate helper function that only returns the the shortest-movement from the current head position so I can continually call this function.
Is the best way to do this to simply pass in another variable to hold the distance and keep checking based on this number? and then remove that disk from the list once I've satisfied the movement?

In Scheme having accumulators and state as extra parameters to a helper function and update using recursion to have state during the execution without actually mutating bindings.
The simplest example:
(define (reverse lst)
(let loop ((lst lst) (acc '()))
(if (null? lst)
acc
(loop (cdr lst) (cons (car lst) acc)))))
(reverse '(1 2 3)) ; ==> (3 2 1)
EDIT
Now since you said you're not used to named let here is the same with a helper procedure and keeping the same names:
(define (reverse lst)
;; a helper with an accumulator
(define (loop lst acc)
(if (null? lst)
acc
(loop (cdr lst) (cons (car lst) acc))))
;; call the helper
(loop lst '()))
Now the names loop, lst, acc are just variable names. However their names suggest loop is a tail recursive procedure. lst is a list and acc is short for accumulator which indicates on the base case it will be part of the result and for the default case it will be updated.

Related

Why does my lazy filtered list in scheme consume so much memory?

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.

Implementing powerset in scheme

I am trying to implement a powerset function in Scheme in two ways.
One way is using tail recursion, and I did it like this:
(define (powerset list)
(if (null? list) '(()) ;; if list is empty, its powerset is a list containing the empty list
(let ((rest (powerset (cdr list)))) ;; define "rest" as the result of the recursion over the rest of list
(append (map (lambda (x) (cons (car list) x)) rest) ;; add the first element of list to the every element of rest (which is a sublist of rest)
rest)))) ;; and append it to rest itself (as we can either use the current element (car list), or not
Which works fine.
Another way is using foldr, and this is where I face some issues.
My current implementation is as follows:
(define (powerset-fr list)
(foldr (lambda (element result) ;; This procedure gets an element (and a result);
(if (null? result) ;; if starting with the empty list, there is nothing to "fold over".
(cons '() (cons element result))
(foldr (lambda (inner-element inner-result)
(append (cons element result) inner-result))
'(())
result)))
'() ;; The result is initialized to the empty list,
list)) ;; and the procedure is being applied for every element in the first list (list1)
Which yields a poor result.
I'll try to explain shortly how did I approach this problem so far:
foldr runs over every element in the given set. For each such element, I should add some new elements to the powerset.
Which elements should these be? One new element for each existing element in the powerset, where is append the current element in list to the existing element in powerset.
This is why I thought I should use foldr twice in a nested way - one to go over all items in given list, and for each item I use foldr to go over all items in "result" (current powerset).
I faced the problem of the empty list (nothing is being added to the powerset), and thus added the "if" section (and not just foldr), but it doesn't work very well either.
I think that's it. I feel close but it is still very challenging, so every help will be welcomed.
Thanks!
The solution is simpler, there's no need to use a double foldr, try this:
(define (powerset-fr lst)
(foldr (lambda (e acc)
(append (map (lambda (x) (cons e x))
acc)
acc))
'(())
lst))
If your interpreter defines append-map or something equivalent, then the solution is a bit shorter - the results will be in a different order, but it doesn't matter:
(define (powerset-fr lst)
(foldr (lambda (e acc)
(append-map (lambda (x) (list x (cons e x)))
acc))
'(())
lst))
Either way, it works as expected:
(powerset-fr '(1 2 3))
=> '((1 2 3) (1 2) (1 3) (1) (2 3) (2) (3) ())

Scheme,level intermediate student, find min without recursion

How can I write a function using abstract list functions (foldr, map, and filter) without recursion that consumes a list of numbers (list a1 a2 a3 ...) and produces a new list removing the minimum number from the original list?
The recursion code is:
(define (find-min lst)
(cond
[(empty? (rest lst)) (first lst)]
[else
(local [(define min-rest (find-min (rest lst)))]
(cond
[(< (first lst) min-rest) (first lst)]
[else min-rest]))]))
A fold applies a 2-argument function against a given value and the car of a list uses the result against the successive cars or the cdrs or the list. this is what we want.
Whereas map returns a new list by doing something with each element of a list.
And filter returns a smaller or equal list based on some predicate.
Now just to formulate a function that can choose the lessor of two arguments
(define (the-lessor x y)
(if (< x y)
x
y))
From there implementation is straightforward.
(define (min L) (fold the-lessor (car L) (cdr L)))
Since this looks like a homework question, I'm not going to provide all the code, but hopefully push you in the right direction.
From the HTDP book, we see that "The Intermediate Student language adds local bindings and higher-order functions." The trick here is probably going to using "local bindings".
Some assumptions:
(remove-min-from-list '()) => not allowed: input list must be non-empty
(remove-min-from-list '(1)) => '()
(remove-min-from-list '(1 2 3 1 2 3)) => '(2 3 2 3) ; all instances of 1 were removed
Somehow, we need to find the minimum value of the list. Call this function min-of-list. What are its inputs and outputs? It's input is a list of numbers and its output is a number. Of the abstract list functions, which ones allow us to turn a list of numbers into a number? (And not another list.) This looks like foldl/foldr to me.
(define (min-of-list lst)
(foldr some-function some-base lst))
Since you already showed that you could write min-of-list recursively, let's move on. See #WorBlux's answer for hints there.
How would we use this in our next function remove-min-from-list? What are the inputs and outputs of remove-min-from-list? It takes a list of numbers and returns a list of numbers. Okay, that looks like map or filter. However, the input list is potentially shorter than that output list, so filter and not map.
(define (remove-min-from-list lst)
....
(filter some-predicate list))
What does some-predicate look like? It needs to return #f for the minimum value of the list.
Let's pull this all together and use local to write one function:
(define (remove-min-from-list lst)
(local [(define min-value ...)
(define (should-stay-in-list? number) ...min-value ...)]
(filter should-stay-in-list? lst)))
The key here, is that the definition for should-stay-in-list? can refer to min-value because min-value came before it in the local definitions block and that the filter later on can use should-stay-in-list? because it is in the body of the local.
(define (comparator n) (local [(define (compare v) (not (equal? v n)))] compare))
(define (without-min list) (filter (comparator (foldr min (foldr max 0 list) list)) list))

Scheme: a good set function

I need to write a good set function that checks whether its argument lst is a properly represented set, i.e. it is a list consisting only of integers, with no duplicates, and returns true #t or false #f. For example:
(good-set? (1 5 2)) => #t
(good-set? ()) => #t
(good-set? (1 5 5)) => #f
(good-set? (1 (5) 2)) => #f
so I have began writing the function as:
(define (good-set? lst)
so I don't know how to proceed after this. Can anybody help?
One option would be to use andmap and sets, as has been suggested by #soegaard:
(define (good-set? lst) ; it's a good set if:
(and (andmap integer? lst) ; all its elements are integers and
(= (length lst) ; the list's length equals the size
(set-count (list->set lst))))) ; of a set with the same elements
But if you can't use sets or other advanced procedures, then traverse the list and test if the current element is an integer and is not present somewhere else in the list (use member for this), repeating this test for each element until there are no more elements in the list. Here's the general idea, fill-in the blanks:
(define (good-set? lst)
(cond (<???> ; if the list is empty
<???>) ; then it's a good set
((or <???> ; if the 1st element is not an integer or
<???>) ; the 1st element is in the rest of the list
<???>) ; then it's NOT a good set
(else ; otherwise
(good-set? <???>)))) ; advance recursion
Sets are built into the Racket standard library: I would recommend not reimplementing them in terms of lists unless you really need to do something customized.
If we need to treat this as a homework assignment, I would recommend using a design methodology to systematically attack this problem. In this case, see something like How to Design Programs with regards to designing functions that work on lists. As a brief sketch, we'd systematically figure out:
What's the structure of the data I'm working with?
What tests cases do I consider? (including the base case)
What's the overall shape of the function?
What's the meaning of the natural recursion?
How do I combine the result of the natural recursion in order to compute a solution to the total?
For this, check if the first number is duplicated, if it is not, then recurse by checking the rest. As such:
(define (good-set? list)
(or (null? list) ; nothing left, good!
(let ((head (car list)))
(rest (cdr list)))
(and (number? head) ; a number
(not (member = head rest)) ; not in the rest
(good-set? rest))))) ; check the rest
If you need member, then
(define (member pred item list)
(and (not (null? list))
(or (pred item (car list))
(member pred item (cdr list)))))

Remove element off list

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))))))

Resources