Scheme: Update a list without using imperative features like set - scheme

I have only just started to learn scheme and were asked to implement the quick-sort algorithm in scheme, but we are not allow to use any imperative features like set! and we are not allowed to use filter
I have tried to come up with my own algorithm with this in mind, but I can't seem to avoid the use of set! for updating a list:
(define quicksort
(lambda (L)
(cond
[(or (null? L) (null? (cdr L))) L]
[else (let ((pivot (car L)) (small '()) (large '()))
(do ((i (- (length L) 1) (- i 1)))
((= i 0))
(if (< (list-ref L i) pivot)
(set! small (cons (list-ref L i) small))
(set! large (cons (list-ref L i) large))))
(append (quicksort small) (list pivot) (quicksort large)))])))
This code works, but is there any way of updating the lists small and large without the use of set?

If you cannot use set!, you cannot mutate lists. You are being asked to do this functionally, without any mutation. Instead of modifying a list in-place, build up smaller, partially-sorted lists and then combine them while preserving the sort.

To be fair Quicksort is an in place algorithm and many would state replacing the vectors with lists will change it enough to no longer bee quicksort. I'll ignore this at the moment.
Split large stuff in smaller chunks of code. This way you can test each step:
(segment 5 '(5 1 1 3 8 6 4 9 8 5 3 5 3 8 6))
; ==> ((1 1 3 4 3 3) (5 5) (8 6 9 8 8 6))
Of course you make the simple tests first:
(segment 5 '(5)) ; ==> (() (5) ())
(segment 5 '(5 1)) ; ==> ((1) (5) ())
(segment 5 '(5 8)) ; ==> (() (5) (8))
(segment 5 '(5 8 1 5)) ; ==> ((1) (5 5) (8))
The order of the results in the sub list is not important. eg. the result ((3 3 4 3 1 1) (5 5) (6 8 8 9 6 8)) is equally as sufficient and most probably easier to do.
With that made quicksort by first checking if it is a less than 2 element list eg. (or (null? lst) (null? (cdr lst))) and return the argument or create the 3 segments using the first element as pivot and then append the recursion of the lesser and the higher and then appending the 3 lists together and you have them in order.
As inspiration here is a procedure that splits on odd? and not:
(define (split-odd lst)
(let loop ((lst lst) (odd '()) (even '()))
(cond
((null? lst) (list odd even))
((odd? (car lst)) (loop (cdr lst) (cons (car lst) odd) even))
(else (loop (cdr lst) odd (cons (car lst) even))))))
(split-odd '(1 2 3 4 5 6))
; ==> ((5 3 1) (6 4 2))

Related

How to invert the predicate here?

I have the following filter procedure:
; (2) filter
(define (filter test sequence)
; return a list of the elements that pass the predicate test
(let ((elem (if (null? sequence) nil (car sequence)))
(rest (if (null? sequence) nil (cdr sequence))))
(cond ((null? sequence) nil)
((test elem) (cons elem (filter test rest)))
(else (filter test rest)))))
And here would be an example of using it to return the even-numbered elements of a list:
(define even? (lambda (x) (= (modulo x 2) 0)))
(define sequence '(1 2 3 4 5 8 9 11 13 14 15 16 17))
(filter even? sequence)
; (2 4 8 14 16)
Is there a simple way to use the not test to invert the selection? For example, I thought the following might work:
(filter (not even?) sequence)
But it returns an error. I can define odd separately, of course:
(define odd? (lambda (x) (not (even? x))))
But I'm trying not to do this. Is there a way to write the odd procedure without defining it directly, but instead using the not directly like I'm trying to do above?
There is a complement function in Common Lisp that does what I think you are looking for. complement is a higher-order procedure that takes a procedure as its argument, and returns a procedure that takes the same arguments as the input procedure and performs the same actions, but the returned truth value is inverted.
Racket has a similar procedure, negate, and it is easy enough to implement this in Scheme:
(define (complement f)
(lambda xs (not (apply f xs))))
> (filter even? '(1 2 3 4 5))
(2 4)
> (filter (complement even?) '(1 2 3 4 5))
(1 3 5)
> (> 1 2 3 4 5)
#f
> ((complement >) 1 2 3 4 5)
#t
And in Racket:
scratch.rkt> (filter even? '(1 2 3 4 5))
'(2 4)
scratch.rkt> (filter (negate even?) '(1 2 3 4 5))
'(1 3 5)
scratch.rkt> (> 1 2 3 4 5)
#f
scratch.rkt> ((negate >) 1 2 3 4 5)
#t
The general answer to this is to simply compose not and the function you care about. Racket has a compose function which does this, but you can easily write a simple one yourself:
(define (compose-1 . functions)
;; simple-minded compose: each function other than the last must
;; take just one argument; all functions should return just one
;; value.
(define (compose-loop fns)
(cond
((null? fns)
(λ (x) x))
((null? (cdr fns))
(car fns))
(else
(λ (x) ((car fns) ((compose-loop (cdr fns)) x))))))
(compose-loop functions))
Making it efficient and more general takes more work of course.
Then you can define odd? (which is already defined of course):
(define odd? (compose-1 not even)
Or in fact define a more general CL-style complement function:
(define (complement f)
(compose-1 not f))
One option is to write an invert function which will curry things along (so the initial function still accepts one argument) until the final evaluation occurs:
(define invert (lambda (func) (lambda (x) (not (func x)))))
(define sequence '(1 2 3 4 5 6 8 9 11 13 14 15 16 17))
(filter (invert even?) sequence)
; (1 3 5 9 11 13 15 17)

How to make two lists, one with even numbers and one with odd numbers, in scheme?

I have a problem.
For example:
We have one unsorted list:
(1 4 5 3 6 7)
Can you help me make 2 lists?
One odd numbered, increasing list:
(1 3 5 7)
and the other even numbered, decreasing list:
(6 4)
Don't use sort!
(define (split filter lst)
(let loop ((a '()) (b '()) (lst lst))
(if (null? lst)
(values a b)
(let ((cur (car lst)))
(if (filter cur)
(loop (cons cur a) b (cdr lst))
(loop a (cons cur b) (cdr lst)))))))
(split odd? '(1 2 3 4 5 6 7 8 9 10))
; ==> (9 7 5 3 1), (10 8 6 4 2)
Now, to make one that separates odds from evens and in a specific order would be simple.

Printing Numbers in Scheme

Im trying to do the following in the list below: Let say list one consists of (1234) and list 2 is (5678) I am trying to print it in the following way (15263748) This is what I have for now but I am not sure where to go after this. Of course right now the code below prints it like 12 34 it should be 1 3 2 4
(define (arrange-list lst1 lst2)
(append lst1 lst2))
(arrange-list '(12) '(34))
This is a common procedure, usually known as interleave. Assuming that the input lists have the same length, we can write the following implementation from scratch, using explicit recursion:
(define (interleave lst1 lst2)
(if (null? lst1)
'()
(cons (car lst1)
(interleave lst2 (cdr lst1)))))
The trick is taking one element from one list, and then from the other until both lists are exhausted. A more idiomatic solution in Racket would be to use built-in procedures, like this:
(define (interleave lst1 lst2)
(flatten (map cons lst1 lst2)))
Either way it works as expected:
(interleave '(1 2 3 4) '(5 6 7 8))
=> '(1 5 2 6 3 7 4 8)
If the lists aren't of equal length, this is my solution which works albeit is not as elegant as the one mentioned in the other answer.
Basically, we maintain a variable x while recursively calling the procedure that indicates which list needs processing currently. The first list is indicated by 1 and the second, 2.
(define (print-alt A B x)(cond
((and (null? A) (null? B)) '())
((= 1 x) (cond
((null? A) (print-alt A B 2))
(else (append (list (car A)) (print-alt (cdr A) B 2)))))
(else (cond
((null? B) (print-alt A B 1))
(else (append (list (car B)) (print-alt A (cdr B) 1)))))))
Here is the output:
(print-alt (list 1 2 3 4 5 6) (list 5 6 7 8 9 10 11 12 123) 1)
(1 5 2 6 3 7 4 8 5 9 6 10 11 12 123)

finding subsets of length N of a list in scheme

I wrote a function which finds all the subsets of a list already and it works. I'm trying to write a second function where I get all the subsets of N length, but it's not working very well.
This is my code:
(define (subset_length_n n lst)
(cond
[(empty? lst) empty]
[else (foldr (lambda (x y) (if (equal? (length y) n) (cons y x) x)) empty (powerset lst))]
))
where (powerset lst) gives a list of all the subsets.
Am I misunderstanding the purpose of foldr?
I was thinking that the program would go through each element of the list of subsets, compare the length to n, cons it onto the empty list if there the same, ignore it if it's not.
But (subset_length_n 2 (list 1 2 3)) gives me (list (list 1 2) 1 2 3) when I want (list (list 1 2) (list 1 3) (list 2 3))
Thanks in advance
When using foldr you don't have to test if the input list is empty, foldr takes care of that for you. And this seems like a job better suited for filter:
(define (subset_length_n n lst)
(filter (lambda (e) (= (length e) n))
(powerset lst)))
If you must, you can use foldr for this, but it's a rather contrived solution. You were very close to getting it right! in your code, just change the lambda's parameters, instead of (x y) write (y x). See how a nice indentation and appropriate parameter names go a long way toward writing correct solutions:
(define (subset_length_n n lst)
(foldr (lambda (e acc)
(if (= (length e) n)
(cons e acc)
acc))
empty
(powerset lst)))
Anyway, it works as expected:
(subset_length_n 4 '(1 2 3 4 5))
=> '((1 2 3 4) (1 2 3 5) (1 2 4 5) (1 3 4 5) (2 3 4 5))

Do iterative loop in scheme

New to scheme here and I'm having some trouble learning do loops. I am attempting to make a function that will take in an object and a vector, and then iterate through the vector until it find that object. When the object is found, it would then return a list containing all of the items in the vector before the object. My code is below. All it will return is how many iterations the do loop went through, instead of the list I want it to. If anyone could help me with the syntax, I would greatly appreciate it. Thanks! ( ideally this would return (1 2))
(define(vector-test-iterative X Vector)
(do ((i 0 (+ i 1))) (< i (vector-length Vector))
(if (eqv? X (vector-ref Vector i))
(= i (vector-length Vector))
(cons (vector-ref Vector i) (ls '())))
ls))
(vector-test-iterative '4 #(1 2 4 3 5))
If you're using Racket, then there's no need to use do, which was never popular among schemers anyway. There's a whole range of iterators -- look for for in the docs, and things that start with for. For example, your code boils down to
#lang racket
(define (values-before x vector)
(for/list ([y (stop-before (in-vector vector)
(lambda (y) (eqv? x y)))])
y))
(If you really want to use do, then you're missing a pair of parens around the test, and you should add a binding for the accumulator.)
A solution that uses a named loop. Cleaner (in my opinion!) than the do version and should work on any R5RS Scheme:
;; Extracts the sublist of `lst` up to `val`.
;; If `val` is not found, evaluates to an empty list.
(define (upto val lst)
(let loop ((res null) (lst lst))
(cond ((null? lst) null)
((eq? val (car lst)) (reverse res))
(else (loop (cons (car lst) res) (cdr lst))))))
;; Adapts the above procedure to work with vectors.
(define (vector-upto val vec)
(list->vector (upto val (vector->list vec))))
;; test
(vector-upto 6 #(1 2 3 4 5))
=> #0()
(vector-upto 5 #(1 2 3 4 5))
=> #4(1 2 3 4)
(vector-upto 3 #(1 2 3 4 5))
=> #2(1 2)
(vector-upto 1 #(1 2 3 4 5))
=> #0()

Resources