loop through tree and sum all values in racket? - racket

I am try to write some generic method that takes two arguments (tree , function)to iterate over tree node and pass tree node to method
for example i have this method called fold that take binary search tree as first argument and function as second argument while argument method takes four arguments (key value left-node-key right-node-key).
(define (fold tree function)
(cond
[(null? tree) (function '() '() '() '())]
[(number? (car tree))
(+ (funct (car tree) (cadr tree) (caaddr tree) (car(cadddr tree)))
(fold (cddr(caddr tree)) function)
(fold (cddr(cadddr tree)) function)
)]
[else (function '() '() '() '())]
)
)
here is some methods that could be passed to above fold method :
first method could be sumAll
(define (sumAll key value leftValue rightValue)
(if (null? key)
0
(+ key leftValue rightValue)
)
)
second method could be findMinimum
(define (findMinimum key value leftValue rightValue)
(if (null? key)
'()
(if (null? leftValue)
key
leftValue
)
)
)
use:
(define tr '(20 "20" (18 "18" ()(19 "19" () ())) (21 "21" (15 "15" () ()) ()) ))
(fold tr sumAll ) ; should return: 93
(fold tr findMinimum ) ; should return: 15
but i am getting this error from fold method:
+: contract violation
expected: number?
given: '()
argument position: 2nd
other arguments...:
any clue why i am getting this error.

You can make fold abstract enough by accepting any procedure proc and a base case value init, and have the procedure apply the argument function over all nodes as follows:
(define (fold proc init lst)
(cond
[(null? lst) init]
[else
(proc (car lst)
(fold proc init (caddr lst))
(fold proc init (cadddr lst)))]))
Then, with the following binary search tree example definition:
(define BST '(20 "20" (18 "18" () (19 "19" () ())) (21 "21" (15 "15" () ()) ())))
you can use the procedure as:
(fold + 0 BST) ; find sum
=> 93
(fold min 1000 BST) ; find min
=> 15

Related

How to concatenate all the elements of the argument lists into a single list

I am trying to concatenate all elements in the list argument into a single list.
I have this code:
(define (concatenate . lsts)
(let rec ([l lsts]
[acc '()])
(if (empty? l)
acc
(rec (cons (list* l)
acc)))))
An example of output is here:
> (concatenate '(1 2 3) '(hi bye) '(4 5 6))
'(1 2 3 hi bye 4 5 6)
But I keep getting this error:
rec: arity mismatch;
the expected number of arguments does not match the given number
expected: 2
given: 1
Can someone please explain this?
Another answer explains the OP error,
and shows how the code can be fixed using append.
But there could be reasons for append to be disallowed in this assignment
(of course, it could be replaced with, for example, an inner "named let" iteration).
This answer will present an alternative approach and describe how it can be derived.
#lang racket
(require test-engine/racket-tests)
(define (conc . lols) ;; ("List of Lists" -> List)
;; produce (in order) the elements of the list elements of lols as one list
;; example: (conc '(1 2 3) '(hi bye) '(4 5 6)) => '(1 2 3 hi bye 4 5 6)
(cond
[(andmap null? lols) empty ] ;(1) => empty result
[else
(cons (if (null? (car lols)) ;(2) => head of result
(car (apply conc (cdr lols)))
(caar lols))
(apply conc ;(3) => tail of result
(cond
[(null? (car lols))
(list (cdr (apply conc (cdr lols)))) ]
[(null? (cdar lols))
(cdr lols) ]
[else
(cons (cdar lols) (cdr lols)) ]))) ]))
(check-expect (conc '() ) '())
(check-expect (conc '() '() ) '())
(check-expect (conc '(1) ) '(1))
(check-expect (conc '() '(1) ) '(1))
(check-expect (conc '() '(1 2) ) '(1 2))
(check-expect (conc '(1) '() ) '(1))
(check-expect (conc '(1) '(2) ) '(1 2))
(check-expect (conc '(1 2) '(3 4) ) '(1 2 3 4))
(check-expect (conc '(1 2 3) '(hi bye) '(4 5 6)) '(1 2 3 hi bye 4 5 6))
(test)
Welcome to DrRacket, version 8.6 [cs].
Language: racket, with debugging; memory limit: 128 MB.
All 8 tests passed!
>
How was this code derived?
"The observation that program structure follows data structure is a key lesson in
introductory programming" [1]
A systematic program design method can be used to derive function code from the structure
of arguments. For a List argument, a simple template (natural recursion) is often appropriate:
(define (fn lox) ;; (Listof X) -> Y ; *template*
;; produce a Y from lox using natural recursion ;
(cond ;
[(empty? lox) ... ] #|base case|# ;; Y ;
[else (... #|something|# ;; X Y -> Y ;
(first lox) (fn (rest lox))) ])) ;
(Here the ...s are placeholders to be replaced by code to create a particular list-argumented
function; eg with 0 and + the result is (sum list-of-numbers), with empty and cons it's
list-copy; many list functions follow this pattern. Racket's "Student Languages" support
placeholders.)
Gibbons [1] points out that corecursion, a design recipe based on result structure, can also
be helpful, and says:
For a structurally corecursive program towards lists, there are three questions to ask:
When is the output empty?
If the output isn’t empty, what is its head?
And from what data is its tail recursively constructed?
So for simple corecursion producing a List result, a template could be:
(define (fn x) ;; X -> ListOfY
;; produce list of y from x using natural corecursion
(cond
[... empty] ;(1) ... => empty
[else (cons ... ;(2) ... => head
(fn ...)) ])) ;(3) ... => tail data
Examples are useful to work out what should replace the placeholders:
the design recipe for structural recursion calls for examples that cover all possible input variants,
examples for co-programs should cover all possible output variants.
The check-expect examples above can be worked through to derive (1), (2), and (3).
[1] Gibbons 2021 How to design co-programs
Assuming you are allowed to call append, for simplicity. You have
(define (concatenate . lsts)
(let rec ([l lsts]
[acc '()])
(if (empty? l)
acc
(rec (cons (list* l) ; only ONE
acc) ; argument
))))
calling rec with only one argument. I have added a newline there so it becomes more self-evident.
But your definition says it needs two. One way to fix this is
(define (conc . lsts)
(let rec ([ls lsts]
[acc '()])
(if (empty? ls)
acc
(rec (cdr ls) ; first argument
(append acc (car ls)) ; second argument
))))
Now e.g.
(conc (list 1 2) (list 3 4))
; => '(1 2 3 4)
I used append. Calling list* doesn't seem to do anything useful here, to me.
(edit:)
Using append that way was done for simplicity. Repeatedly appending on the right is actually an anti-pattern, because it leads to quadratic code (referring to its time complexity).
Appending on the left with consequent reversing of the final result is the usual remedy applied to that problem, to get the linear behavior back:
(define (conc2 . lsts)
(let rec ([ls lsts]
[acc '()])
(if (empty? ls)
(reverse acc)
(rec (cdr ls)
(append (reverse (car ls))
acc)))))
This assumes that append reuses its second argument and only creates new list structure for the copy of its first.
The repeated reverses pattern is a bit grating. Trying to make it yet more linear, we get this simple recursive code:
(define (conc3 . lols)
(cond
[(null? lols) empty ]
[(null? (car lols))
(apply conc3 (cdr lols)) ]
[else
(cons (caar lols)
(apply conc3
(cons (cdar lols) (cdr lols))))]))
This would be even better if the "tail recursive modulo cons" optimization was applied by a compiler, or if cons were evaluated lazily.
But we can build the result in the top-down manner ourselves, explicitly, set-cdr!-ing the growing list's last cell. This can be seen in this answer.

Check if element is in a tree

I need to write a function in Lisp that checks if an element N is in a tree TREE.
(defun TREE-CONTAINS (N TREE)
(cond ((equal TREE nil) nil)
((listp (CAR TREE)) (or (TREE-CONTAINS(N (CAR TREE)))
(TREE-CONTAINS(N (CDR TREE)))))
(t (cond ((equal N (CAR TREE)) t)
(t TREE-CONTAINS(N (CDR TREE)))))
)
)
For example, (TREE-CONTAINS (1 ((1 2 3) 4 5))) will return true. But I keep getting an error that says "Undefined function N called with arguments ((2 3))" when I test my code with this example: (TREE-CONTAINS 2 '(1 2 3)). Of course N is supposed to be 1 here but I don't know why it thinks N is a function. Any idea?
In the call to tree-contains, or any lisp function, you should not include parentheses around the arguments. It's (function-name arg1 arg2), not (function-name (arg1 arg2)).
So for a start, remove the parentheses around the arguments to the call (tree-contains(n (car tree))) like so: (tree-contains n (car tree)). Similarly for the next call to tree-contains in that or clause. Besides, the last condition: (t TREE-CONTAINS(N (CDR TREE))) should be called like this: (t (tree-contains n (cdr tree))).

I am new to Racket and need some help for this function

I want the answer to be #t here:
> (is-member? "foo" '(4 5 #f "foo" a))
#t
But I'm getting the error:
> (is-member? "foo" '(4 5 #f "foo" a))
;string=?: contract violation
; expected: string?
; given: #f
; argument position: 2nd
; other arguments...:
; "foo"
My definitions of is-member? and is-member-string? are:
#lang racket
(define (is-member? num lst)
(if (null? lst)
#f
(if (string? num)
(is-member-string? num lst)
(is-member-number? num lst))))
(define (is-member-string? num lst)
(if (null? lst)
#f
(if (integer? (car lst))
(is-member-string? num (rest lst))
(if (string=? (car lst) num)
#t
(is-member-string? num (rest lst))))))
(define (is-member-number? num lst)
....)
Look at the error message and see how it helps you. It says the error is coming from string=?, and if you look in DrRacket it even highlights the specific call that went wrong. It's the (string=? (car lst) num) in the is-member-string? function.
Figure out what arguments were and why they're wrong. The error message says that the wrong argument was #f where it expected a string.
Where did the bad argument come from? Was it num or (car lst)? Looking at how num flows through the program, num should always be "foo", so it's probably the other one, (car lst).
How did this code execute with that bad argument? Why is (car lst) false here? Because it's walking down the list, and the list contains a false in it. That should be fine, as long as you design your function properly to handle all values.
To do that, you should put a type signature on your functions to show what types of arguments are allowed. For is-member-string? I'm assuming you meant:
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
....)
(I've renamed num to str because it's not a number, it's a string.)
Next you need to make sure that the code works with the signature. You're designing this function by destructuring the list argument, but you need to keep the types of the values in mind:
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
(if (null? lst)
#f
(.... (first lst) ; (first lst) is an Any
.... (rest lst)))) ; (rest lst) is a [List-of Any]
(I'm using first instead of car because first makes more sense.)
Can you see what's wrong now?
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
(if (null? lst)
#f
(if (integer? (first lst)) ; (first lst) is an Any
(is-member-string? str (rest lst))
(if (string=? (first lst) str) ; (first lst) is an Any, but not an integer
#t
(is-member-string? str (rest lst))))))
(first lst) is an Any, but you're using (string=? (first lst) str). That shouldn't be allowed unless you're sure that (first lst) is a string.
There are two ways to do this. One way to fix this is to use (equal? (first lst) str) instead.
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
(if (null? lst)
#f
(if (equal? (first lst) str)
#t
(is-member-string? str (rest lst)))))
The second way is to check that it's a string before you use string=?. I assume that's what you were trying to do with your integer? check, but it isn't working. Instead you want to use (string? (first lst)) somehow. You only want to check string=? after that passes. One way to do that is with and.
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
(if (null? lst)
#f
(if (and (string? (first lst)) (string=? (first lst) str))
#t
(is-member-string? str (rest lst)))))

funcall function error cannot take car lisp

What's wrong with this code?
(defun f (l)
(funcall #'(lambda (ff)
(cond
((null l)nil)
((listp (car l)) (append ff (f (cdr l)) (car ff)))
(t (list (car l)))))
(f (car l))))
If I enter (f '(( 1 2 3))) it gives me an error:
"Cannot take car of 1".
What's wrong?
Here is a more detailed explanation of the comment of #Sylwester, that answers correctly to the question.
If you write (f '((1 2 3)) then the function f is called, l is bound to ((1 2 3)), and the result is the application of the internal function (lambda (ff) (cond ...)) to the value of (f (car l)).
To perform this application, first (f (car l)) is evaluated to produce a value, and since l is bound to ((1 2 3)), its car is (1 2 3).
So, f is applied to the list (1 2 3), which is bound to l in the recursive call. This evaluation again means that fshould apply the internal function (lambda (ff) (cond ...)) to the value of (f (car l)), that is to (f 1).
The process is reapeated, l is bound this time to 1, and again fshould apply the internal function (lambda (ff) (cond ...)) to the value of (f (car l)), but, since l is now 1, the function tries to evaluate the (car 1), which produces the error that you have found.

Map! procedure in Racket

The map! procedure should modify the existing list to have the values of the operator applied to the original values.
For example:
(define a '(1 2 3 4 5))
(define double (lambda (x) (* x 2)))
(map! double a)
returns
done
Then when a is evaluated, a should return
(2 4 6 8 10)
map! procedure must do that work.
(define (map! operator given-list)
(if (null? given-list) 'done
(<the procedure that does the modification>)))
My guess1:
(map (lambda (x) (set! x (operator x))) given-list)
(map! double a)
returns:
'(#<void> #<void> #<void> #<void> #<void>)
My guess2:
(cons (operator (car given-list)) (map! double (cdr given-list)))
(map! double a)
returns:
'(2 4 6 8 10 . done)
My guess3:
(set! given-list (map operator given-list))
(map! double a)
returns:
'(2 4 6 8 10)
My guess4:
(let ((element (car given-list)))
(set! element (operator given-list) (map! operator (cdr given-list)))
(map! double a)
returns:
'done
but, when "a" is evaluated, it still says:
'(1 2 3 4 5)
What do I have to do for this?????
You cannot use set! for this. You need to use set-car! on the cons cell you're changing. Here's how you might write it:
(define (map! f lst)
(let loop ((rest lst))
(unless (null? rest)
(set-car! rest (f (car rest)))
(loop (cdr rest)))))
If you have SRFI 1, it's even easier (if we ignore for a moment that SRFI 1 already defines map! ;-)):
(define (map! f lst)
(pair-for-each (lambda (pair)
(set-car! pair (f (car pair))))
lst))