How do I write the test case for this code? - scheme

I've just started learning about trees and heaps and I'm unsure about how to go about writing the test case. These codes are from my lesson slides. Although they give codes, they sadly don't provide test cases of said codes, so I am confused on how I would call it.
I've tried test cases such as any regular integers like 5, and I've also tried going about it with lists, but I run into errors and it just doesn't seem right as I know from diagrams that heaps are like trees with its roots being the smallest value and with its subheaps.
(define (value H)
(car H))
(define (weight H)
(cdr H))
(define (create-heap vw-pair left-child right-child)
(list vw-pair left-child right-child))
(define (h-min heap)
(car heap))
(define (left heap)
(cadr heap))
(define (right heap)
(caddr heap))
(define (insert vw-pair heap)
(cond ((null? heap) (create-heap vw-pair '() '()))
((< (weight vw-pair) (weight (h-min heap)))
(create-heap vw-pair (right heap) (insert (h-min heap) (left heap))))
(else
(create-heap (h-min heap) (right heap) (insert vw-pair (left heap))))))
(define (insert-list-of-pairs vw-pair-list heap)
(if (null? vw-pair-list)
heap
(insert-list-of-pairs (cdr vw-pair-list) (insert (car vw-pair-list) heap))))
(define (remove-min heap)
(define (combine-heaps h1 h2)
(cond ((null? h1) h2)
((null? h2) h1)
((< (cdr (h-min h1)) (cdr (h-min h2)))
(create-heap (h-min h1) h2 (combine-heaps (left h1) (right h1))))
(else
(create-heap (h-min h2)
h1
(combine-heaps (left h2) (right h2))))))
(combine-heaps (left heap) (right heap)))

Your test cases should explain exactly what you want to do.
They are the way to explain, using code, the intended use for the functions you write.
For your specific case, I obviously can't help you because that's exactly what's missing from your code: the meaning it should have.
But I can still explain how to write unit tests in Racket:
;; This is a function you would write.
;; It does something, but it's not completely obvious
;; how to use it.
(define (find type basket)
(let ([obj (assq type basket)])
(and obj
(cadr obj))))
;; By creating a test module, you add code that describes
;; how to use the functions in this file.
(module+ test
(require rackunit)
;; This is some sample data.
;; It's useful to understand what kind of data
;; your functions are expected to process.
(define basket '((bread baguette)
(fruit ananas)
(fruit banana)
(vegetable carrot)
(misc fork&knife)))
;; Here we call the function and show the expected result.
;; It's now clear how to use it.
(check-equal? (find 'fruit basket) 'ananas)
(check-equal? (find 'vegetable basket) 'carrot)
(check-false (find 'fruit '()))
)
You can run those tests by using raco:
> raco test myfile.rkt
raco test: (submod "myfile.rkt" test)
3 tests passed

Related

car: contract violation expected: pair? given: () during remove in binary search tree

I don't understand how I am getting a contract violation. It seems when I create a bst it doesnt make 2 empty lists it just has ().
This is my remove method:
;Returns the binary search tree representing bst after removing x where f and g are predicates as defined in bst-contains.
(define (bst-remove bst f g x)
;if empty return empty
(cond ((empty? bst) (bst-create-empty)))
;else if equal then check right if right is empty then pull from left
(cond ((g (car bst) x) (cond ((empty? (caddr bst)) (cond ((empty? (cadr bst)) (bst-create-empty))
(else (car(cadr bst)))))
;if right isnt empty then remove from left
(else(bst-create (bst-max-right (caddr bst)) (cadr bst) (bst-remove (caddr bst) f g (bst-max-right (caddr bst)))))))
(else (bst-create (car bst) (bst-remove (cadr bst) f g x) (bst-remove (caddr bst) f g x)))))
My bst-create and bst-create-empty:
;Returns an empty binary search tree.
(define (bst-create-empty)
'())
;Returns a binary search tree having the specified root value, with left-subtree left and right-subtree right.
(define (bst-create root left right)
(list root left right))
The code I give it is
(bst-remove (bst-create 5 (bst-create 6 (bst-create-empty) (bst-create-empty)) (bst-create 4 (bst-create-empty) (bst-create-empty))) < = 6)
The error i get is car: contract violation expected: pair? given: ()
You have got Scheme and especially cond all wrong. If you in a body of a procedure have two statements like:
(define (test lst)
first-expression
tail-expression)
It is obvious that the tail-expression will follow the evaluation and discarding of any result of the first-expression. Also unless first-expression has side effects it is dead code. Your cond expressions (cond ((empty? bst) (bst-create-empty))) is dead code since no matter what the outcome is it will never be a part of the result since Scheme will evaluate the second cond unconditionally. It does (car bst) which throws the error.
The correct way to have multiple returns are by one expression:
(cond
(test1 consequent1)
(test2 consequent2)
(test3 consequent3)
(else alternative))
Needless to say all the previous tests are negative so if test3 is true, then you know that test1 and test2 both had negative results. You also know that if consequent1 is evaluated no other terms or tests gets evaluated. It stops at the first prositive.
In you specific case the code could have looked like this:
(define (bst-remove bst f g x)
(cond ((empty? bst)
(bst-create-empty))
((not (g (car bst) x))
(bst-create (car bst) (bst-remove (cadr bst) f g x) (bst-remove (caddr bst) f g x)))
((not (empty? (caddr bst)))
(bst-create (bst-max-right (caddr bst)) (cadr bst) (bst-remove (caddr bst) f g (bst-max-right (caddr bst)))))
((empty? (cadr bst))
(bst-create-empty))
(else
(caadr bst))))
Using nested if works too, but it makes harder to read code just like your nested cond. Notice that I negated some of the tests since they only have one alternative but several tests in its consequent. By negating I could have one consequent and continue testing for the other cases in the same cond.
You refer to your second cond as an else if in your comment, but it's not an else-if, it's just an if. That is, you check the second condition even if the first one was true, in which case the car part of the condition causes this error.
To fix this, you should make both conditions part of a single cond, in which case it will actually act like an else if.
It looks like you've misunderstood cond, or possibly Scheme in general.
The result of a function application is the value of the last expression in the function's body (the only reason for having more than one is if you're doing something that has a side effect), and cond expressions are evaluated in exactly the same way as other Scheme expressions.
So the expression (cond ((empty? bst) (bst-create-empty))) does not return an empty tree, it is evaluated and produces an empty tree, and that tree is discarded.
Then evaluation continues with the next cond, which is a bad idea when the tree is empty.
A further problem is that the function should produce a tree, but (car (cadr bst)) wouldn't.
If you define a few useful accessor functions:
(define bst-value car)
(define bst-left cadr)
(define bst-right caddr)
then these lines are more obviously wrong:
(cond ((empty? (bst-left bst)) (bst-create-empty))
(else (bst-value (bst-left bst)))))
Fixing it, it becomes (reasonably) clear that the entire expression
(cond ((empty? (bst-left bst)) (bst-create-empty))
(else (bst-left bst))))
is equivalent to
(bst-left bst)
Now you have
(cond ((empty? (bst-right bst)) (bst-left bst))
( else make a tree...
But there's a lack of symmetry here; surely, if the left subtree is empty, the result should be the entire right subtree in a similar way.
So,
(cond ((empty? (bst-right bst)) (bst-left bst))
(empty? (bst-left bst)) (bst-right bst))
( else make a tree...
But now we can spot another problem: even in these cases, we need to recurse into the subtrees before we're done.
I'll digress here because too many accessor repetitions and conds makes code pretty unreadable.
Using a couple of lets (and getting rid of the unused f parameter), I ended up with this:
(define (bst-remove tree g x)
(if (empty? tree)
(bst-create-empty)
;; If the tree isn't empty, we need to recurse.
;; This work is identical for all the cases below, so
;; lift it up here.
(let ([new-left (bst-remove (bst-left tree) g x)]
[new-right (bst-remove (bst-right tree) g x)])
;; Build an appropriate tree with the new subtrees.
(if (g (bst-value tree) x)
(cond [(empty? new-left) new-right] ;; If either new subtree is empty,
[(empty? new-right) new-left] ;; use the other.
;; The complicated case. Get the new node value from the
;; right subtree and remove it from there before using it.
[else (let ([new-value (bst-max-right new-right)])
(bst-create new-value
new-left
(bst-remove new-right g new-value)))])
;; The straightforward case.
(bst-create (bst-value tree)
new-left
new-right)))))

how do you sum tree in scheme

;; A [BT X] is one of
;; - 'leaf
;; - (make-node X [BT X] [BT X])
(define-struct node (val left right))
;; interpretation: represents a node with a value
;; a left and right subtree
(define (tree-sum tree)
(cond
[(symbol=? tree 'leaf) ...] ;; the value remains same
[(node? tree)
(+ (tree-sum (node-val tree))
(tree-sum (node-left tree))
(tree-sum (node-right tree)))]))
not quite sure if i'm on the right track.
Normally, A pair tree is either
a leaf (not a pair), or
a pair, whose car and cdr values are pair-trees.
recursive summing procedure will have to deal with these two cases:
a numbers, i.e., leaves of a tree of numbers, and
pairs, in which case it should sum the left and right subtrees, and add those sums together.
Therefore,
(define (pair-tree-sum pair-tree)
(cond
[(number? pair-tree)
pair-tree]
[else
(+ (pair-tree-sum (car pair-tree))
(pair-tree-sum (cdr pair-tree)))]))
You can split the function into two parts - one that converts the tree into a list of numbers, and another that just uses foldl with that list, and foldl has the advantage of automatically doing the summation as an accumulator.
(define (tree->list tree)
(if (pair? tree)
(append (tree->list (car tree))
(tree->list (cdr tree)))
(list tree)))
(define (tree-sum tree)
(foldl + 0 (tree->list tree)))
You first need to check if the tree is empty, then if its not a list, else you call the function sum to the car of the list, and add to the cdr of the list.
(define (sum tree)
(cond [(empty? tree) 0]
[(not (list? tree)) (if (number? tree) tree 0)]
[else (+ (sum (first tree)) (sum (rest tree)))]))

Scheme and Merge Sort?

I was assigned to write a merge sort in Scheme but I have some issues with it. I showed it my professor and he said there is one simple mistake. Can someone help me?
Plzz!
(define msort
(lamdba(1st)
(cond
((null?? 1st) 1st)
((null? (cdr 1st)) 1st)
(#t ((letrec ((half (quotient (lenght 1st) 2))
(merge (lamdba (a b result)
(cond ((null? a) (apped (reserve a) result))
((null? b) (append (reserve a) result))
((> (car a) (car b) (merge a (cdr b) (cons (car b) result))
(#t (merge (cdr a) b (cons (car a) result)))))))
(merge (msort (take 1st half)) (msort (drop 1st half)) '()))))))
One simple mistake? He probably referred to #1, but even after fixing that you have some identifiers and parenthesis to fix:
lambda, null?, length, append, and reverse is spelled incorrectly.
letrec result gets applied since you have excess parenthesis around it.
cond in merge where you compare elements are missing parenthesis two places.
It's obvious you need help with parenthesis matching so you should download a decent IDE to write code in. I use DrRacket for Scheme development (#!R5RS, #!R6RS and #!racket) and it idents (just press CTRL+i to get it reidented after pasting in code) and indicate where function names are written wrong when you hit RUN.
Making merge a global function in the beginning and perhaps move it to a letrec later (if you have to) might ease development. Eg. you could find errors by testing stuff like (merge '(3 2 1) '()).
This is no guarantee the program will work since I only address syntax here. You need to debug it! DrRacket has a debugger too!
I think it is useful to implement first a function that allow to merge two ordered lists:
(define (merge l1 l2)
(if (empty? l1)
l2
(if (empty? l2)
l1
(if (< (car l1) (car l2))
(cons (car l1) (merge (cdr l1) l2))
(cons (car l2) (merge l1 (cdr l2)))))))
Now assume we have a function (get ls pos) capable to return the element of ls in position pos:
(define (get ls pos)
(if (= pos 1)
(car ls)
(get (cdr ls) (- pos 1))))
Finally, we can implement mergesort function:
(define (mergesort l p r)
(if (= p r)
(cons (get l p) empty)
(merge (mergesort l p (floor (/ (+ p r) 2))) (mergesort l (+ (floor (/ (+ p r) 2)) 1) r))))

Scheme Error, Return Binary Search Tree as Ordered List (R5RS)

I am a noob at Scheme. I have a binary search tree. The format of a node is a list of three elements, the first being the value at the node, the second being the left child node, and the third being the right child node. The "make" function creates an empty tree that looks like this: ( () () () ). I am able to create the tree, insert values, and find if a certain value exists in the tree. My problem comes when I try to write a function that returns the tree as an ordered list. Insert and Make functions:
;Inserts a number into the tree
(define (insert t x)
(cond ((null? (car t))
(list x (make) (make)))
((< x (car t))
(list (car t) (insert (cadr t) x) (caddr t)))
((> x (car t))
(list (car t) (cadr t) (insert (caddr t) x) ))
)
)
;Makes a new empty tree
(define (make)
(list (list) (list) (list))
)
Those works fine. Here is my as-list:
;Gives list of all numbers
(define (as-list t)
(cond
(
(null? (car t) )
(list)
)
(
#t
(append (as-list (cadr t)) (as-list (car t)) (as-list (caddr t)))
)
)
)
Running this, I get a contract violation, saying it expected "mpair?". I do not believe this is a logic error on my part, but it may be. Is this another parentheses problem?
Thank you for your time!
Your recursion should be
(append (as-list (cadr t)) (list (car t)) (as-list (caddr t)))
You only want to call as-list on trees, and the car of your t is not a tree.

Deleting an element from a BST in scheme

I can't seem to figure out how to delete an element from the BST. This is my code
(define remove (lambda (x t)
(if (< x (car t)) (list (car t) (remove x (cadr t)) (caddr t))
(if (> x (car t)) (list (car t) (cadr t) (remove x (caddr t)))
(if (not(and (null? (cadr t)) (null? (caddr t))))
(let ((r (minimum (caddr t)))) ((remove r t) (set-car! t r)))
(list '() (cadr t) (caddr t)))))))
Minimum returns the minimum value in the tree.
If I try to delete an element that's not a leaf, it goes into an infinite loop. How can I fix it?
I think your biggest problem lies in this section:
((remove r t) (set-car! t r))
You are removing r from t, but you should really be removing r from the right subtree of t. I'm not sure why you are using mutability/setting, either; I think it complicates things in what could easily be a non-side effecting function. I would try something like:
(list r (cadr t) (remove r (caddr t)))
I also have to admit that I'm a bit confused about your intent with the last line. What are you using the empty list for?
As an alternative, you can take a look here for the whole implementation of BST in scheme:
http://en.literateprograms.org/Binary_tree_(Scheme)
It is very well documented and would give you a bit of insight about the way you can structure the code to be easy to read and debug. Especially, it treats leaf and node (non-leaf) removals separately.

Resources