I need help on two problems for my computer science class. The problems are below.
Write a function contains-all? that consumes two lists of numbers and returns true if the first list contains all elements of the second one and false otherwise. For simplicity assume that neither list contains the same element more than once.
Write a function common-elements that takes two lists of numbers and returns the list of all elements that appear in both lists.
For number 1 I have the following code so far:
(define (contains-all? lon lon2)
(cond
[(and (empty? lon) (empty? lon2)) true]
[(or (empty? lon) (empty? lon2)) false
[(equal? (first lon) (first lon2)) (contains-all? (rest lon) (rest lon2))]
[else false]))
My check-expects are the following:
(check-expect (contains-all? empty empty) true)
(check-expect (contains-all? empty (list 1 2 3)) false)
(check-expect (contains-all? (list 1 2 3) empty) false)
(check-expect (contains-all? (list 1 2 3) (list 3 2 1)) true)
(check-expect (contains-all? (list 1 2 4 6 8) (list 6 8 4)) true)
(check-expect (contains-all? (list 1 2 8 6) (list 1 2 6 4)) false)
I know some of the check-expects will fail and that is what I need help with.
For problem 2 I have this so far
(define (common-elements lon lon2)
(cond
[(and (empty? lon) (empty? lon2)) empty]
[(or (empty? lon) (empty? lon2)) empty]
[(equal? (first lon) (first lon2))
(cons (first lon) (common-elements (rest lon) (rest lon2)))]
[(not (equal? (first lon) (first lon2))) (common-elements (first lon) (first lon2))]
;[else (common-elements (first lon) (rest lon2))]))
Check expects are the following:
(check-expect (common-elements empty empty) empty)
(check-expect (common-elements empty (list 1 2)) empty)
(check-expect (common-elements (list 1 2) empty) empty)
(check-expect (common-elements (list 1 2 3) (list 1 2 4)) (list 1 2))
(check-expect (common-elements (list 3 2 1) (list 2 1)) (list 2 1))
I have the same problem with number 2 and need help on them.
As #uselpa points out, a lot depends on whether the numbers in the lists are guaranteed to be sorted. Your problem statement suggests no, but your code suggests yes. Do you have this guarantee? I'm guessing the answer is no.
Next: you suggest that this is a problem that requires generative recursion, but this doesn't appear to be the case. Specifically, both of these functions look like a straightforward instance of HtDP's Processing Two Lists Simultaneously: Case 1.
If your instructor is claiming that these require generative recursion, I claim that your instructor is mistaken :).
However, I can say that both of these problems will be substantially easier if you use the "wish list" approach to describe needed functions as you're building the main function.
Also, as #Renzo points out, you appear to have a bug in at least one of your test cases; the list containing 1,2, and 3 certainly contains all of the elements in the empty list.
Related
So, I am trying to do this hw problem: write a function that takes two arguments, a list and a number, and the function returns the index of the leftmost occurrence of the number in the list. For example:
If '(1 2 3 3 4) and num = 3, then it returns 2
If '(3 2 3 3 4) and num = 3, then it returns 0
I was able to do that part but what if the number was never found? What if I want to return false when num is not found in the list? How do I do that?
Please remember, I am trying to do this in proper recursion, not tail recursion.
Here's my code.
(define (first_elt_occ lst num)
(cond
((null? lst) #f)
((eq? (car lst) num) 0)
(else
(+ 1 (first_elt_occ (cdr lst) num)))))
(first_elt_occ '(1 2 3 3 4) 3) ;2
(first_elt_occ '(3 2 3 3 4) 3) ;0
(first_elt_occ '(1 2 5 4 3) 3) ;4
(first_elt_occ '(1 2 5 4 3) 6) ;Error
;(makes sense because you can't add boolean expression)
Another question I have is, how would I approach this problem, if I was asked to return the index of the rightmost occurrence of the number in a list (proper recursion). For example: '(3 4 5 4 3 7 ), num = 3 returns 4.
Thank you!
As suggested in the comments, this will be easier if we implement the procedure using tail recursion - by the way, tail recursion is "proper recursion", what makes you think otherwise?
By defining a helper procedure called loop and passing the accumulated result in a parameter, we can return either #f or the index of the element:
(define (first_elt_occ lst num)
(let loop ((lst lst) (acc 0))
(cond
((null? lst) #f)
((equal? (car lst) num) acc)
(else (loop (cdr lst) (add1 acc))))))
If, for some bizarre requirement you can't use tail recursion in your solution, it's possible to rewrite you original solution to account for the case when the answer is #f - but this isn't as elegant or efficient:
(define (first_elt_occ lst num)
(cond
((null? lst) #f)
((equal? (car lst) num) 0)
(else
(let ((result (first_elt_occ (cdr lst) num)))
(if (not result) #f (add1 result))))))
Either way, it works as expected:
(first_elt_occ '(1 2 3 3 4) 3) ; 2
(first_elt_occ '(3 2 3 3 4) 3) ; 0
(first_elt_occ '(1 2 5 4 3) 3) ; 4
(first_elt_occ '(1 2 5 4 3) 6) ; #f
I don't recommend actually taking this approach because a normal tail-recursive implementation is a lot more efficient, simpler, and easier to understand, but you can use a continuation to short-circuit unwinding the call stack in the failure case:
(define (first_elt_occ lst num)
(call/cc
(lambda (return)
(letrec ((loop (lambda (lst)
(cond
((null? lst) (return #f))
((= (car lst) num) 0)
(else (+ 1 (loop (cdr lst))))))))
(loop lst)))))
The basic find first occurrence "skeleton" function is
(define (first_elt_occ lst num)
(and (not (null? lst))
(or (equal (car lst) num)
(first_elt_occ (cdr lst) num))))
This does not return index though. How to add it in?
(define (first_elt_occ lst num)
(and (not (null? lst))
(or (and (equal (car lst) num) 0)
(+ 1 (first_elt_occ (cdr lst) num)))))
Does it work? Not if the element isn't there! It'll cause an error then. How to fix that? Change the +, that's how!
(define (first_elt_occ lst num)
(let ((+ (lambda (a b) (if b (+ a b) b))))
(and (not (null? lst))
(or (and (= (car lst) num) 0)
(+ 1 (first_elt_occ (cdr lst) num))))))
And now it works as expected:
> (first_elt_occ '(1 2 3 3 4) 3)
2
> (first_elt_occ '(3 2 3 3 4) 3)
0
> (first_elt_occ '(3 2 3 3 4) 5)
#f
And to get your second desired function, we restructure it a little bit, into
(define (first_elt_occ lst num)
(let ((+ (lambda (a b) ...... )))
(and (not (null? lst))
(+ (and (= (car lst) num) 0)
(first_elt_occ (cdr lst) num)))))
Now, what should that new + be? Can you finish this up? It's straightforward!
It's unclear why you are opposed to tail recursion. You talk about "proper recursion", which is not a technical term anyone uses, but I assume you mean non-tail recursion: a recursive process rather than an iterative one, in SICP terms. Rest assured that tail recursion is quite proper, and in general is preferable to non-tail recursion, provided one does not have to make other tradeoffs to enable tail recursion.
As Óscar López says, this problem really is easier to solve with tail recursion. But if you insist, it is certainly possible to solve it the hard way. You have to avoid blindly adding 1 to the result: instead, inspect it, adding 1 to it if it's a number, or returning it unchanged if it's false. For example, see the number? predicate.
I'm trying to write a function that checks if a given list is spiraling (numbers going from negative to positive while the abs value of the numbers is strictly increasing)
EX:
(check-expect
(spiraling? (cons 1 (cons -10 (cons 100 empty))))
true)
Im not entirely sure even where my error is so i made slight adjustments in my writing that hasnt done anything.
(define (spiraling? list-of-int)
(cond
[(empty? list-of-int) true]
[(and (number? (first list-of-int))
(empty? (rest list-of-int))) true]
[(and (< (abs (first list-of-int))
(abs (first (rest (first list-of-int)))))
(cond
[(and (> 0 (first list-of-int))
(< 0 (first (rest (first list-of-int)))))true]
[(and (< 0 (first list-of-int))
(> 0 (first (rest (first list-of-int)))))true]
[else false]))
(cond
[(empty? list-of-int) true]
[else (spiraling? (rest list-of-int))])]))
(check-expect
(spiraling? (cons 1 (cons -10 (cons 100 empty))))
true)
(check-expect
(spiraling? (cons -1 (cons 2 (cons -3 (cons 4 empty)))))
true)
(check-expect
(spiraling? (cons 99 (cons -100 (cons 100 empty))))
false)
(check-expect
(spiraling? (cons 0 (cons -10 (cons 100 empty))))
false)
But instead it comes out as:
:: rest: expects a non-empty list; given: ()
Your program has many incoherences.
First, the argument of the function should be a list of integers, but sometimes you use it as a list of lists, for instance when you write:
(abs (first (rest (first list-of-int)))))
in fact (first list-of-int) should return an integer (the first element of the list), but then you apply to it rest, which is an operator that applied to a non empty list returns the list without the first element. And this is the reason of the error message (“rest expect a non-empty list but received 1”).
If you want the second element of a list, you can do (first (rest list)), or, better, (second list). These are basic operators of the language.
Second, in the second branch of the cond, you check to see if the first element of the list is a number, but this check is not repeated in the third branch, even if you use both the first and the second elment as numbers. So the test is useless, since it is applied only in certain cases to certain elements of the list. You should apply to all or none of the elements, to be consistent.
Third, in the last branch of the cond, in the last two lines, you check again if the list is empty, but at this point of the program the list is certainly not empty, since you have tested at least two elements!
Here is a possible solution (without checking if all the elements are numbers):
(define (spiraling? list-of-int)
(if (or (empty? list-of-int) (empty? (rest list-of-int)))
true
(let ((first-element (first list-of-int))
(second-element (second list-of-int)))
(if (or (< first-element 0 second-element)
(> first-element 0 second-element))
(spiraling? (rest list-of-int))
false))))
I'd like to write the following ex:
(adjoin-set 2 (adjoin-set 8 (adjoin-set 4 (adjoin-set 3 (adjoin-set 7 (adjoin-set 5 '()))))))
recursively.
My other code is as follows (from Structure and Interpretation of Computer Programs, 2nd ed.)
(define (entry tree) (car tree))
(define (left-branch tree) (cadr tree))
(define (right-branch tree) (caddr tree))
(define (make-tree entry left right)
(list entry left right))
(define (adjoin-set x set)
(cond ((null? set) (make-tree x '() '()))
((= x (entry set)) set)
((< x (entry set))
(make-tree (entry set)
(adjoin-set x (left-branch set))
(right-branch set)))
((> x (entry set))
(make-tree (entry set)
(left-branch set)
(adjoin-set x (right-branch set))))))
So far I've tried the following:
(define (bst list)
(if (null? list) '())
(bst (adjoin-set (cdr list) '())))
This doesn't work. How could I make this work?
I'd like to follow a similar approach as when making the calls manually, i.e., (adjoin-set (car list) (next adjoint-set)).
First, rather than working a binary search tree for representing sets, I'll just use lists with no duplicate elements. The point is that we'll write a method to adjoin a single element, and then figure out how to call it with repeatedly with multiple values and get the final result. You'll still be able to apply this approach to your tree-based implementation.
Representing sets with lists containing no duplicates
If we represent sets by lists with no duplicates, then a single adjoin just takes an element and a list and returns the list if the element is already in the list, or a new list created from the new element and the old list, if the list doesn't contain it. So, adjoin isn't too hard:
(define (member? element list)
(cond
((null? list) #f)
((eqv? (car list) element) #t)
(else (member? element (cdr list)))))
(define (adjoin element set)
(if (member? element set)
set
(cons element set)))
This is counterpart of what you've already got with adjoin-set from SICP.
Performing more than one operation
Now, if you want to be able to adjoin a bunch of elements onto some initial value, you're performing a reduction, or fold. There are lots of variant implementations of reduce or fold (and foldr, foldl, etc.), but a quick and simple left-associative version is:
(define (reduce function list initial-value)
(if (null? list)
initial-value
(reduce function
(cdr list)
(function (car list) initial-value))))
Now, you can reduce your adjoin function over a list of elements of and get the final result:
(define (adjoin* elements set)
(reduce adjoin elements set))
Here are two examples that adjoin a bunch of elements to some preexisting sets. In the first case, the set is the empty set. In the second case, it's the set (1 2 3 4). Of course, to make this work with your code, those initial sets will need to be tree-based sets.
(display (adjoin* '(5 7 3 4 8 2) '()))
;;=> (2 8 4 3 7 5)
(display (adjoin* '(5 7 3 4 8 2) '(1 2 3 4)))
;;=> (8 7 5 1 2 3 4)
With the following code, I get #<CompilerException java.lang.UnsupportedOperationException: Can only recur from tail position (NO_SOURCE_FILE:4)> despite the fact that all recurs are in tail positions. If I remove the recur from the one-argument version, it stops complaining. Why is this happening?
(defn remove-duplicates "Removes duplicate elements of lst.
For example, given (1 2 3 1 4 1 2), remove-duplicates returns a sequence
containing the elements (1 2 3 4), in some order."
[lst] (recur (rest lst) (set (first lst)))
[lst uniques] (cond (zero? (count lst)) uniques
:else (cond
(some (partial = (first lst)) uniques)
(recur (rest lst) uniques)
:else
(recur (rest lst) (first lst)))))
You haven't split up the multi-arity bodies right. Should read (defn foo ([x] (...)) ([x y] (...))). This causes the compiler to think you're doing totally different stuff, which probably accounts for your issue.
First of all: you know that all you want is (def remove-duplicates set) or -- if you want a vector -- (def remove-duplicates-vec (comp vec set)), right?
Five things here:
As amalloy noticed, you should've added parens
As kotarak noticed, you can't recur between arities
You can't call (set (first lst)) because set wants coll. If you want, do something like (set (vector (first [1 2 3 2 3]))) but this is neither pretty nor idiomatic
Doing (cond pred1 code1 :else (cond pred2a code2a :else code2b)) could be made simplier: (cond pred1 code1 pred2a code2a :else code2b) -- what you did is treated cond macro as if it were if (which is a built-in as far as I know)
Your last tail-call is also wrong. Assume we've started with [1 2 3 2 1]
When you call it first you have following arguments: ([2 3 2 1] #{1}) (I've skipped the boring part)
Then you have last predicate true, so you go with ([3 2 1] 2) and this is obviously wrong because you wanted ([3 2 1] #{1 2}). You probably want to call (recur (rest lst) (conj uniques (first lst)))
Summing up:
(defn remove-duplicates
([lst] (remove-duplicates (rest lst) #{(first coll)}))
([lst uniques]
(cond
(zero? (count lst)) uniques
(some (partial = (first lst)) uniques)
(recur (rest lst) uniques)
:else
(recur (rest lst) (conj uniques (first lst))))))
Before I start: YES, this is homework from college. Before I get told that I'm lazy and evil: this part of the homework was to convert two functions we already had, this one is the 6th.
(define (flatten-list a-list)
(cond ((null? a-list) '())
((list? (car a-list))
(append (flatten-list (car a-list)) (flatten-list (cdr a-list))))
(else (cons (car a-list) (flatten-list (cdr a-list))))))
The function, as you can guess, flattens a list even if it's nested. My specific problem with the transformation comes in the (list? (car a-list)) condition, in which I'm doing two recursive calls. I already did fibonacci, which I can do by just having two "acummulators" on the tail recursion. However, my mind is not trained in this yet to know how it should go.
I would appreciate if I was given hints and not the result. Thanks!
Here's my solution:
(define (flatten-iter a-list)
(define (flat-do acc lst-interm lst)
(cond
((null? lst)
(reverse acc))
((and (list? lst-interm) (not (null? lst-interm)))
(flat-do acc (car lst-interm) (append (cdr lst-interm) lst)))
((not (list? lst-interm))
(flat-do (cons lst-interm acc) empty lst))
((list? (car lst))
(flat-do acc (car lst) (cdr lst)))
(else
(flat-do (cons (car lst) acc) empty (cdr lst)))))
(flat-do empty empty a-list))
(flatten-iter (list 1 (list 2 (list 3 4 (list 5 empty 6))) 7 8))
=> (1 2 3 4 5 6 7 8)
Tail-recrusive functions require that they never return, and thus you can't use stack for storing your program's state. Instead, you use function arguments to pass the state between function calls. Therefore, we need to determine how to maintain the state. Because the result of our function is list?, it's meaningful to grow an empty list; we're using acc for this purpose. You can see how it works in else branch above. But we should be able to process nested lists. And while we're going deeper, we should keep the rest elements of the nested list for further processing. Sample list: (list 1 (list 2 3) 4 5)
Until (list 2 3) we have already added 1 to accumulator. Since we can't use stack, we need some other place to store the rest elements of the list. And this place is the lst argument, which contains elements of the original list to be flattened. We can just append the lst to the rest elements (cdr (list 2 3)) which are (list 3), and proceed with the list's head we stumbled upon while flattening, i. e. (car (list 2 3)) which is just 2. Now, (and (list? lst-interm) (not (null? lst-interm))) succeeds because flat-do is called this way:
(flat-do (list 1) (list 2 3) (list 4 5))
and the condition triggers this code:
(flat-do (list 1) (car (list 2 3)) (append (cdr (list 2 3)) (list 4 5)))
flat-do again is called this way: (flat-do (list 1) 2 (list 3 4 5))
The condition (not (list? 2)) now succeeds and the code (flat-do (cons 2 1) empty (list 3 4 5)) is evaluated.
The rest processing is done with else branch until lst is null? and reverse is performed on acc. Function then returns the reversed accumulator.