Scheme: Implementing a Quick-Sort - functional-programming

I'm trying to implement a quick sort using scheme, some dudes here already helped me fixing my split function and now I'm asking for you help with combining everything into one working algorithm.
Here is my code so far:
(define quick-sort (lambda (lst)
(define pivot (lambda (lst)
(if (null? lst)
null
(car lst))))
(define split (lambda (lst pivot)
(define lst1 null)
(define lst2 null)
(define split-helper (lambda (lst pivot lst1 lst2)
(if (null? lst)
(list lst1 lst2)
(if (<= (car lst) pivot)
(split-helper (cdr lst) pivot (cons (car lst) lst1) lst2)
(split-helper (cdr lst) pivot lst1 (cons (car lst) lst2))))))
(split-helper lst pivot lst1 lst2)))
(if (null? lst)
null
(append (quick-sort (car (split lst (pivot lst)))) (quick-sort (cdr (split lst (pivot lst))))))))
As you can see, I'm choosing the pivot to simply be the first element in the list, the problem I'm facing is that the program ran into an infinite loop when the pivot is the smallest element in the list because it makes the program choose the same pivot over and over.
Also, the way it's currently implemented makes it be really un-efficient because the split function is called twice with the same lst in every ineration of quick-sort but I just don't have good enough control over Scheme to write it any other way.
I saw some posts about Quick-Sort in Scheme but they were implemented a bit different and I rather try and correct my own implementation than copying some other dude's work.
Thank you.

This is a classical mistake when it comes to quicksort. Your pivot should not be a part of the partitions. That way a one element list makes two empty partitions, one before and one after the pivot.
As for doing the same operation twice. Use let to buffer the split result and use the variable twice.

Removed excessive lambdas, aliases, bindings, and reformatted, but didn't change or annotate semantics (Sylwester already pointed out the bug):
(define (quick-sort lst)
(define (pivot lst)
(if (null? lst)
'()
(car lst) ))
(define (split lst pivot)
(let split-helper ((lst lst) ; Named let instead of internal
(lst1 '()) ; definition
(lst2 '()) )
(if (null? lst)
(cons lst1 list2)
(if (<= (car lst) pivot)
(split-helper (cdr lst)
(cons (car lst) lst1)
lst2)
(split-helper (cdr lst)
lst1
(cons (car lst) lst2) )))))
(if (null? lst)
'()
(let ((spl (split lst (pivot lst)))) ; Memoization of the `split`
(append (quick-sort (car spl))
(quick-sort (cdr spl)) ))))
I think you're trying to implement a partition:
(define (partition pred xs)
(let part ((ps '()) (ns '()) ; Initial "positives" `ps`, and "negatives" `ns`
(xs' xs) )
(if (null? xs')
(cons ps ns) ; Returning pair of lists
(let ((x (car xs'))) ; Memoization of `(car lst)`
(if (pred x)
(part (cons x ps) ns (cdr xs'))
(part ps (cons x ns) (cdr xs')) )))))
(define (quicksort xs)
(if (null? xs) '()
(let* ((x (car xs))
(pn (partition ; Memoization of `partition`
(lambda (x')
(< x' x) )
(cdr xs) )))
(append (quicksort (car pn)) ; Extracting positives from pair
(list x) ; Pivot
(quicksort (cdr pn)) )))) ; Negatives
(display
(quicksort (list 4 2 3 5 1)) ) ; (1 2 3 4 5)
part is inefficient in strict languages like Scheme; it copies all three of its arguments for every recursive step. Often, straightforward formulations in terms of basic folds like filter and map are most efficient. A much more efficient implementation using filter:
(define (quicksort xs)
(if (null? xs) '()
(let ((x (car xs))
(xs' (cdr xs)) )
(append (quicksort
(filter (lambda (x')
(< x' x) )
xs'))
(list x)
(quicksort
(filter (lambda (x')
(>= x' x) )
xs'))))))
This strategy famously happens to be very briefly expressible in functional languages.
In lazy Haskell, a single-traversal partition is actually more efficient than filtering twice.
select :: (a -> Bool) -> ([a], [a]) -> a -> ([a], [a])
select pred (ps, ns) x | pred x = (x : ps, ns)
| otherwise = (ps, x : ns)
partition :: (a -> Bool) -> [a] -> ([a], [a])
partition pred = foldl (select pred) ([], [])
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (x : xs) = let (lt, gt) = partition (< x) xs
in quicksort lt ++ [x] ++ quicksort gt

Related

Option type encoding / robustness in Lisp

(define (nth n lst)
(if (= n 1)
(car lst)
(nth (- n 1)
(cdr lst) )))
is an unsafe partial function, n may go out of range. An error can be helpful,
(define (nth n lst)
(if (null? lst)
(error "`nth` out of range")
(if (= n 1)
(car lst)
(nth (- n 1)
(cdr lst) ))))
But what would a robust Scheme analogue to Haskell's Maybe data type look like?
data Maybe a = Nothing | Just a
nth :: Int -> [a] -> Maybe a
nth _ [] = Nothing
nth 1 (x : _) = Just x
nth n (_ : xs) = nth (n - 1) xs
Is just returning '() adequate?
(define (nth n lst)
(if (null? lst) '()
(if (= n 1)
(car lst)
(nth (- n 1)
(cdr lst) ))))
It's easy to break your attempt. Just create a list that contains an empty list:
(define lst '((1 2) () (3 4)))
(nth 2 lst)
-> ()
(nth 100 lst)
-> ()
The key point that you're missing is that Haskell's Maybe doesn't simply return a bare value when it exists, it wraps that value. As you said, Haskell defines Maybe like so:
data Maybe a = Nothing | Just a
NOT like this:
data Maybe a = Nothing | a
The latter is the equivalent of what you're doing.
To get most of the way to a proper Maybe, you can return an empty list if the element does not exist, as you were, but also wrap the return value in another list if the element does exist:
(define (nth n lst)
(if (null? lst) '()
(if (= n 1)
(list (car lst)) ; This is the element, wrap it before returning.
(nth (- n 1)
(cdr lst) ))))
This way, your result will be either an empty list, meaning the element did not exist, or a list with only one element: the element you asked for. Reusing that same list from above, we can distinguish between the empty list and a non-existant element:
(define lst '((1 2) () (3 4)))
(nth 2 lst)
-> (())
(nth 100 lst)
-> ()
Another way to signal, that no matching element was found, would be to use multiple return values:
(define (nth n ls)
(cond
((null? ls) (values #f #f))
((= n 1) (values (car ls) #t))
(else (nth (- n 1) ls))))
This comes at the expense of being a little bit cumbersome for the users of this function, since they now have to do a
(call-with-values (lambda () (nth some-n some-list))
(lambda (element found?)
... whatever ...))
but that can be alleviated by using some careful macrology. R7RS specifies the let-values syntax.
(let-values (((element found?) (nth some-n some-list)))
... whatever ...)
There are several ways to do this.
The direct equivalent would be to mimic the Miranda version:
#!r6rs
(library (sylwester maybe)
(export maybe nothing maybe? nothing?)
(import (rnrs base))
;; private tag
(define tag-maybe (list 'maybe))
;; exported tag and features
(define nothing (list 'nothing))
(define (maybe? v)
(and (pair? v)
(eq? tag-maybe (car v))))
(define (nothing? v)
(and (maybe? v)
(eq? nothing (cdr v))))
(define (maybe v)
(cons tag-maybe v)))
How to use it:
#!r6rs
(import (rnrs) (sylwester maybe))
(define (nth n lst)
(cond ((null? lst) (maybe nothing))
((zero? n) (maybe (car lst)))
(else (nth (- n 1) (cdr lst)))))
(nothing? (nth 2 '()))
; ==> #t
Exceptions
(define (nth n lst)
(cond ((null? lst) (raise 'nth-nothing))
((zero? n) (car lst))
(else (nth (- n 1) (cdr lst)))))
(guard (ex
((eq? ex 'nth-nothing)
"nothing-value"))
(nth 1 '())) ; ==> "nothing-value"
Default value:
(define (nth n lst nothing)
(cond ((null? lst) nothing)
((zero? n) (car lst))
(else (nth (- n 1) (cdr lst)))))
(nth 1 '() '())
; ==> '()
Deault value derived from procedure
(define (nth index lst pnothing)
(cond ((null? lst) (pnothing))
((zero? n) (car lst))
(else (nth (- n 1) (cdr lst)))))
(nth 1 '() (lambda _ "list too short"))
; ==> "list too short"
Combination of exception and default procedure
Racket, a Scheme decent, often has a default value option that defaults to an exception or a procedure thunk. It's possible to mimic that behavior:
(define (handle signal rest)
(if (and (not (null? rest))
(procedure? (car rest)))
((car rest))
(raise signal)))
(define (nth n lst . nothing)
(cond ((null? lst) (handle 'nth-nothing nothing))
((zero? n) (car lst))
(else (nth (- n 1) (cdr lst)))))
(nth 1 '() (lambda () 5)) ; ==> 5
(nth 1 '()) ; exception signalled
As a non-lisper I really can't say how idiomatic this is, but you could return the Church encoding of an option type:
(define (nth n ls)
(cond
((null? ls) (lambda (default f) default))
((= n 1) (lambda (default f) (f (car ls))))
(else (nth (- n 1) ls))))
But that's about as complicated to use as #Dirk's proposal. I'd personally prefer to just add a default argument to nth itself.

How to remove the last element in a list using scheme

I have a requirement to return the last negative number in a list, using a recursive procedure. Right now I have a recursive procedure that returns all negative numbers in the list.
(define returnLastNeg
(lambda (lst)
(if (null? lst)
'()
(if (positive? (car lst))
(returnLastNeg (cdr lst))
(cons (car lst) (returnLastNeg (cdr lst)))))))
calling it with (returnLastNeg'(1 -2 -3 4 -5 6)) returns
Output:
'(-2 -3 -5)
I need it to only return -5 though. I tried to modify my procedure to check to see if the last element in the list is positive. If it is, I want to remove the last element and then call the procedure again. But when I do that I get an error (below)
Modified procedure:
(define returnLastNeg-modified
(lambda (lst)
(if (null? lst)
'()
(if (positive? (last lst))
(remove (last lst) (lst))
(cons (car lst) (returnLastNeg-modified (cdr lst)))))))
ERROR:
application: not a procedure;
expected a procedure that can be applied to arguments
given: '(1 -2 -3 4 -5 6)
arguments...: [none]
>
A simpler approach would be with a helper procedure (called "sub") in this example:
(define returnLastNeg
(lambda (lst)
(define sub
(lambda (lst last-neg)
(if (null? lst)
last-neg
(let ((c (car lst)))
(sub (cdr lst)
(if (negative? c) c last-neg))))))
(sub lst null)))
EDIT
Knowing that
(define <procedureName> (lambda (<params>) ... )
is the same as
(define (<procedureName> <params>) ... )
and reformatting a little, this becomes:
(define (returnLastNeg lst)
(define (sub lst last-neg)
(if (null? lst)
last-neg
(let ((c (car lst)))
(sub (cdr lst) (if (negative? c) c last-neg)))))
(sub lst null))
I hope it's clearer
last-neg gets set to null by the very last expression
the recursive call to sub has 2 parameters (split on 2 lines in the initial version, but newlines don't matter).
This is the same as the even shorter version
(define (returnLastNeg lst)
(let sub ((lst lst) (last-neg null))
(if (null? lst)
last-neg
(let ((c (car lst)))
(sub (cdr lst) (if (negative? c) c last-neg))))))
using a so-called "named let".

Scheme reverse a list

I am trying to reverse a list in Scheme using DrRacket.
Code:
(define rev
(lambda(l)
(if (null? l)
'()
(append (rev (cdr l)) (list (car l))))))
If I input (rev '(a((b)(c d)(((e)))))), the output is (((b) (c d) (((e)))) a).
I want it to be (((((e)))(d c)(b))a). I looked here: How to Reverse a List? but I get an even worse output. What am I doing wrong? Any help would be appreciated!
This is trickier than it looks, you're trying to do a "deep reverse" on a list of lists, not only the elements are reversed, but also the structure … here, try this:
(define (rev l)
(let loop ((lst l)
(acc '()))
(cond ((null? lst) acc)
((not (pair? lst)) lst)
(else (loop (cdr lst)
(cons (rev (car lst))
acc))))))
It works as expected:
(rev '(a ((b) (c d) (((e))))))
=> '(((((e))) (d c) (b)) a)
This code will do it:
(define (rev-list lst)
(if (null? lst)
null
(if (list? lst)
(append (rev-list (cdr lst)
(list (rev-list (car lst))))
lst)))
And the result is:
>>> (display (rev-list '((1 7) 5 (2 4 (5 9))) ))
(((9 5) 4 2) 5 (7 1))
The idea is simple: Return the arg if it's not a list, return rev-list(arg) otherwise.

Recursion on list of pairs in Scheme

I have tried many times but I still stuck in this problem, here is my input:
(define *graph*
'((a . 2) (b . 2) (c . 1) (e . 1) (f . 1)))
and I want the output to be like this: ((2 a b) (1 c e f))
Here is my code:
(define group-by-degree
(lambda (out-degree)
(if (null? (car (cdr out-degree)))
'done
(if (equal? (cdr (car out-degree)) (cdr (car (cdr out-degree))))
(list (cdr (car out-degree)) (append (car (car out-degree))))
(group-by-degree (cdr out-degree))))))
Can you please show me what I have done wrong cos the output of my code is (2 a). Then I think the idea of my code is correct.
Please help!!!
A very nice and elegant way to solve this problem, would be to use hash tables to keep track of the pairs found in the list. In this way we only need a single pass over the input list:
(define (group-by-degree lst)
(hash->list
(foldl (lambda (key ht)
(hash-update
ht
(cdr key)
(lambda (x) (cons (car key) x))
'()))
'#hash()
lst)))
The result will appear in a different order than the one shown in the question, but nevertheless it's correct:
(group-by-degree *graph*)
=> '((1 f e c) (2 b a))
If the order in the output list is a problem try this instead, it's less efficient than the previous answer, but the output will be identical to the one in the question:
(define (group-by-degree lst)
(reverse
(hash->list
(foldr (lambda (key ht)
(hash-update
ht
(cdr key)
(lambda (x) (cons (car key) x))
'()))
'#hash()
lst))))
(group-by-degree *graph*)
=> '((2 a b) (1 c e f))
I don't know why the lambda is necessary; you can directly define a function with (define (function arg1 arg2 ...) ...)
That aside, however, to put it briefly, the problen is that the cars and cdrs are messed up. I couldn't find a way to tweak your solution to work, but here is a working implementation:
; appends first element of pair into a sublist whose first element
; matches the second of the pair
(define (my-append new lst) ; new is a pair
(if (null? lst)
(list (list (cdr new) (car new)))
(if (equal? (car (car lst)) (cdr new))
(list (append (car lst) (list (car new))))
(append (list (car lst)) (my-append new (cdr lst)))
)
)
)
; parses through a list of pairs and appends them into the list
; according to my-append
(define (my-combine ind)
(if (null? ind)
'()
(my-append (car ind) (my-combine (cdr ind))))
)
; just a wrapper for my-combine, which evaluates the list backwards
; this sets the order right
(define (group-by-degree out-degree)
(my-combine (reverse out-degree)))

homework on scheme

how to design a function content which
inputs a single list of atoms lat and which returns
the content of lat.Thus the content of '(a b c a b c d d) is '(a b c d).
The procedure content below should get you what you need.
(define (work x y)
(if (null? (cdr x))
(if (in? (car x) y)
y
(cons (car x) y))
(if (in? (car x) y)
(work (cdr x) y)
(work (cdr x) (cons (car x) y)))))
(define (in? x y)
(if (null? y)
#f
(if (equal? x (car y))
#t
(in? x (cdr y)))))
(define (content x) (work x (list)))
The procedure content accepts a list as a parameter. It sends the list to another procedure called work. This procedure processes the list and adds the items in the list to a new list (if they are not already in the new list). The work procedure makes use of yet another procedure called in, which checks to see if an item is a member of a list.
My solution essentially divides your problem into two sub-problems and makes use of procedures which operate at a lower level of abstraction than your original problem.
Hope that helps.
It is PLT Scheme solution:
(define (is_exists list element)
(cond
[(empty? list) false]
[else
(cond
[(= (first list) element) true]
[else (is_exists (rest list) element)])]))
(define (unique list target)
(cond
[(empty? list) target]
[else
(cond
[(is_exists target (first list)) (unique (rest list) target)]
[else (unique (rest list) (cons (first list) target))])]))
(define (create_unique list)
(unique list empty))
Check it:
> (define my_list (cons '1 (cons '2 (cons '3 (cons '2 (cons '1 empty))))))
> my_list
(list 1 2 3 2 1)
> (create_unique my_list)
(list 3 2 1)
How about little schemer style,
(define (rember-all a lat)
(cond
((null? lat) '())
((eq? a (car lat)) (rember-all a (cdr lat)))
(else (cons (car lat) (rember-all a (cdr lat))))))
(define (content lat)
(cond
((null? lat) '())
(else (cons (car lat)
(content (rember-all (car lat) (cdr lat)))))))
Start from a procedure that simply creates a copy of the passed-in list (very easy to do):
(define (unique-elements seq)
(define (loop ans rest)
(cond ((null? rest) ans)
(else
(loop (cons (car rest) ans)
(cdr rest)))))
(loop '() seq))
To ensure that the output list's elements are unique, we should skip the CONS if the head of REST is already a member of ANS. So we add another condition to do just that:
;;; Create list containing elements of SEQ, discarding duplicates.
(define (unique-elements seq)
(define (loop ans rest)
(cond ((null? rest) ans)
((member (car rest) ans) ; *new*
(loop ans (cdr rest))) ; *new*
(else
(loop (cons (car rest) ans)
(cdr rest)))))
(loop '() seq))
The following function takes in a list and returns a new list with only the unique inputs of it's argument using recursion:
(defun uniq (list)
(labels ((next (lst new)
(if (null lst)
new
(if (member (car lst) new)
(next (cdr lst) new)
(next (cdr lst) (cons (car lst) new))))))
(next list ())))
As was mentioned in the comments, common lisp already has this function:
(defun uniq (list)
(remove-duplicates list))
(define (remove-duplicates aloc)
(cond
((empty? aloc) '())
(else (cons (first aloc)
(remove-duplicates
(filter (lambda (x)
(cond
((eq? x (first aloc)) #f)
(else #t)))
(rest aloc)))))))

Resources