Binary trees in racket - functional-programming

Hi the problem is I want to see if a binary tree is N
We call binary trees, where N be the number of numbers that will contain the list of all nodes. For example this is a binary tree 2:
'((1 2) ((7 10) ((2 4) null null)) ((6 8) ((10 13) null null) null))
And this is a binary tree 1:
'(2- (7- (2 null null) (6 (5 null null) (11 null null))) (5 null (9 (4 null null) null)))
I have this code:
(define (abN? arbol N) (
cond
[(= (length (list-ref list 0)) N) "Arbol Binario N" "No es un arbol binario N" ]
[(= (number? (car list)) N) "Arbol Binario 1" "No es un arbol binario 1" ]
)
)
Then put this in the console:
(abN? '((1 2) ( (7 10) ( (2 4) null null) ) ((6 8) ((10 13) null null) null)) 2)
and give me this error
car: contract violation
expected: pair?
given: #<procedure:list>
What I have been mistaken?
Thank you.

There are several mistakes in your code, try this:
(define (abN? arbol N)
(cond
[(number? (car arbol))
(if (= N 1)
"Arbol Binario 1"
"No es un arbol binario 1")]
[(list? (car arbol))
(if (= (length (car arbol)) N)
"Arbol Binario N"
"No es un arbol binario N")]
[else (error "Dato de entrada incorrecto")]))
Explanation:
The parameter is named arbol, but in your code you're referring to it as list (which by the way, is a built-in function). This is what's causing the error reported
There's no need to use list-ref for accessing the first element of a list, use car instead
You misunderstood how a cond expression works. Each condition evaluates to the last value of the expressions that follow it, if you need to test for further conditions you have to use an if or another cond inside, you seem to believe that each condition has an implicit if-else condition, and that's not correct
First you must verify the type of the first element in the list, otherwise you run the risk of applying a list function over a number, which will result in an error
Finally, it'll be easier to help you if you post the code in English. I can understand Spanish :P , but most people here won't.
It works as expected for the possible inputs:
(abN? '(1 ( (7 10) ( (2 4) null null) ) ((6 8) ((10 13) null null) null)) 1)
=> "Arbol Binario 1"
(abN? '(1 ( (7 10) ( (2 4) null null) ) ((6 8) ((10 13) null null) null)) 2)
=> "No es un arbol binario 1"
(abN? '((1 2) ( (7 10) ( (2 4) null null) ) ((6 8) ((10 13) null null) null)) 2)
=> "Arbol Binario N"
(abN? '((1 2) ( (7 10) ( (2 4) null null) ) ((6 8) ((10 13) null null) null)) 3)
=> "No es un arbol binario N"
(abN? '("bogus" ( (7 10) ( (2 4) null null) ) ((6 8) ((10 13) null null) null)) 3)
=> Unknown input

Related

Clojure - blend of "get" and "nth"?

I am struggling to find a function that will find a happy-medium between the get function and nth. I have been doing a lot of research on these sequence type functions, does anyone know a work around for this or know a function that performs as such?
I need nth's ability to grab sublists:
=> (nth '(1 (2 3) 4 5) 1)
(2 3)
=> (get 1 '(1 (2 3) 4 5))
nil
And I need get's ability to return "nil" when out of range:
=> (get -1 '(1 (2 3) 4 5))
nil
=> (nth '(1 (2 3) 4 5) -1)
Execution error (IndexOutOfBoundsException) at user/eval149 (REPL:1).
null
I need this code for a recursive sub-seq function:
(defn sub-seq [coll i j]
(nth coll i)
(if (< i (+ i j))
(sub-seq coll (inc' i) j)
)
)
(The sub-seq function is supposed to return 'j' elements starting at position 'i'.)
Here are some sample outputs for what I am trying to write:
=> (sub-seq '(1 2 (3 4) (5 (6 7))) 1 2))
(2 (3 4))
=> (sub-seq '(1 2 3 4 5 6 7) 2 4)
(3 4 5 6)
I finally got my function to work, thank you all for your help:
(defn sub-seq [coll i j]
(conj
(list*
(nth coll i nil)
(if (> j 1)
(sub-seq coll (+ i 1) (- j 1))))))
nth takes an optional third argument not-found. You can use it to provide a default value if your index is out of bounds:
user=> (nth '(1 (2 3) 4 5) -1)
Execution error (IndexOutOfBoundsException) at user/eval1 (REPL:1).
null
user=> (nth '(1 (2 3) 4 5) -1 nil)
nil
If you had a vector, you could use subvec directly:
(let [s [1 2 3 4 5 6 7]]
(subvec s 2 6))
If you have a sequence then you could write:
(defn subsequence [coll start n]
(->> coll
(drop start)
(take n)))
(subsequence '(1 2 (3 4) (5 (6 7))) 1 2)
=> (2 (3 4))
(subsequence '(1 2 3 4 5 6 7) 2 4)
=> (3 4 5 6)
Side note: When writing a Clojure program, often you can solve your problem more simply with sequence processing. Sometimes recursive algorithms are necessary, but often you can get by with Clojure's rich set of functions that operate on sequences.
You are misunderstanding get. It works on associative collections like maps and vectors. Consider:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(dotest
(let [data-list '(1 (2 3) 4 5)
data-vec (vec data-list) ]
(spyx (nth data-list 1))
(spyx (nth data-vec 1))
(spyx (get data-list 1))
(spyx (get data-vec 1))
))
with result
(nth data-list 1) => (2 3)
(nth data-vec 1) => (2 3)
(get data-list 1) => nil
(get data-vec 1) => (2 3)
Since a Clojure list is not associative like a map, list should not be used at all with lists. Ideally, get would throw an exception when passed a list argument to indicate it doesn't work with them.
For your specific goal, maybe just do something like:
(take j
(drop i coll))
For additional documentation please review here.

Racket simple procedure for converting number from base 10 to base 4

Im having some problems with racket. The assignment wants me to write a procedure that converts any number from base 10 to base 4, the solution should be written in a list. for example (convert-to-base-four 12) -> (list 3 0)
Now i have written a procedure but it inserts each number in an individual list.
heres my code.
(define (convert-to-base-four number)
(cond
[(<= number 3) (cons number empty)]
[(> number 3) (reverse (list (remainder number 4)
(convert-to-base-four (floor (/ number 4)))))]))
Does anyone know what to do?
Many thanks
AlexKnauth's comment is the one you need to be following – you must define and adhere to a strict domain (input) and codomain (output) for your function
;; from your code
(list Y
(convert-to-base-four X))
It doesn't matter what Y and X are here: if convert-to-base-four returns a list of some value and a recursive call to convert-to-base-four – which returns a list – you're going to end up with a list of lists!
One solution, as another points out, is to use append – but beware, it's a trap
(define (base4 n)
(if (< n 4)
(list n)
(append (base4 (floor (/ n 4)))
(list (remainder n 4)))))
(displayln (base4 12)) ; (3 0)
(displayln (base4 13)) ; (3 1)
(displayln (base4 14)) ; (3 2)
(displayln (base4 15)) ; (3 3)
(displayln (base4 16)) ; (1 0 0)
(displayln (base4 123456)) ; (1 3 2 0 2 1 0 0 0)
A better solution would avoid the costly use of append – here we do that using a named let loop with two loop state variables m and acc
(define (base4 n)
(let loop ((m n) (acc empty))
(if (< m 4)
(cons m acc)
(loop (floor (/ m 4))
(cons (remainder m 4) acc)))))
(displayln (base4 12)) ; (3 0)
(displayln (base4 13)) ; (3 1)
(displayln (base4 14)) ; (3 2)
(displayln (base4 15)) ; (3 3)
(displayln (base4 16)) ; (1 0 0)
(displayln (base4 123456)) ; (1 3 2 0 2 1 0 0 0)
Try to use append on your list :)
Have fun with homework ;)

Common lisp workin with list

my task is to count all element within a list, which have duplicates, eg
( 2 2 (3 3) 4 (3)) will result in 2 (because only 2 and 3 have duplicates)
Searchdeep - just returns a nill if WHAT isn't find in list WHERE
Count2 - go through the single elements and sub-lists
If it finds atom he will use SEARCHDEEP to figure out does it have duplicates, then list OUT will be checked (to make sure if this atom was not already counted (e.g. like ( 3 3 3), which should return 1, not 2)
, increase counter and add atom to the OUT list.
However, i don't understand why, but it constantly returns only 1. I think it is some kind of logical mistake or wrong use of function.
My code is:
(SETQ OUT NIL)
(SETQ X (LIST 2 -3 (LIST 4 3 0 2) (LIST 4 -4) (LIST 2 (LIST 2 0 2))-5))
(SETQ count 0)
(DEFUN SEARCHDEEP (WHAT WHERE) (COND
((NULL WHERE) NIL)
(T (OR
(COND
((ATOM (CAR WHERE)) (EQUAL WHAT (CAR WHERE)))
(T (SEARCHDEEP WHAT (CAR WHERE)))
)
(SEARCHDEEP WHAT (CDR WHERE))
)
)
)
)
(DEFUN Count2 ( input)
(print input)
(COND
((NULL input) NIL)
(T
(or
(COND
((ATOM (CAR input))
(COND
(
(and ;if
(SEARCHDEEP (CAR INPUT) (CDR INPUT))
(NOT (SEARCHDEEP (CAR INPUT) OUT))
)
(and ;do
(Setq Count (+ count 1))
(SETQ OUT (append OUT (LIST (CAR INPUT))))
(Count2 (CDR input))
)
)
(t (Count2 (CDR input)))
)
)
(T (Count2 (CAR input)))
)
(Count2 (CDR input))
)
)
)
)
(Count2 x)
(print count)
First, your code has some big style issues. Don't write in uppercase (some, like myself, like to write symbols in uppercase in comments and in text outside of code, but the code itself should be written in lowercase), and don't put parentheses on their own lines. So the SEARCHDEEP function should look more like
(defun search-deep (what where)
(cond ((null where) nil)
(t (or (cond ((atom (car where)) (equal what (car where)))
(t (searchdeep what (car where))))
(searchdeep what (cdr where))))))
You also should not use SETQ to define variables. Use DEFPARAMETER or DEFVAR instead, although in this case you should not use global variables in the first place. You should name global variables with asterisks around the name (*X* instead of x, but use a more descriptive name).
For the problem itself, I would start by writing a function to traverse a tree.
(defun traverse-tree (function tree)
"Traverse TREE, calling FUNCTION on every atom."
(typecase tree
(atom (funcall function tree))
(list (dolist (item tree)
(traverse-tree function item))))
(values))
Notice that TYPECASE is more readable than COND in this case. You should also use the mapping or looping constructs provided by the language instead of writing recursive loops yourself. The (values) at the end says that the function will not return anything.
(let ((tree '(2 -3 (4 3 0 2) (4 -4) (2 (2 0 2)) -5)))
(traverse-tree (lambda (item)
(format t "~a " item))
tree))
; 2 -3 4 3 0 2 4 -4 2 2 0 2 -5
; No values
If you were traversing trees a lot, you could hide that function behind a DO-TREE macro
(defmacro do-tree ((var tree &optional result) &body body)
`(progn (traverse-tree (lambda (,var)
,#body)
,tree)
,result))
(let ((tree '(2 -3 (4 3 0 2) (4 -4) (2 (2 0 2)) -5)))
(do-tree (item tree)
(format t "~a " item)))
; 2 -3 4 3 0 2 4 -4 2 2 0 2 -5
;=> NIL
Using this, we can write a function that counts every element in the tree, returning an alist. I'll use a hash table to keep track of the counts. If you're only interested in counting numbers that will stay in a small range, you might want to use a vector instead.
(defun tree-count-elements (tree &key (test 'eql))
"Count each item in TREE. Returns an alist in
form ((item1 . count1) ... (itemn . countn))"
(let ((table (make-hash-table :test test)))
(do-tree (item tree)
(incf (gethash item table 0)))
(loop for value being the hash-value in table using (hash-key key)
collect (cons key value))))
(let ((tree '(2 -3 (4 3 0 2) (4 -4) (2 (2 0 2)) -5)))
(tree-count-elements tree))
;=> ((2 . 5) (-3 . 1) (4 . 2) (3 . 1) (0 . 2) (-4 . 1) (-5 . 1))
The function takes a keyword argument for the TEST to use with the hash table. For numbers or characters, EQL works.
Now you can use the standard COUNT-IF-function to count the elements that occur more than once.
(let ((tree '(2 -3 (4 3 0 2) (4 -4) (2 (2 0 2)) -5)))
(count-if (lambda (item)
(> item 1))
(tree-count-elements tree)
:key #'cdr))
;=> 3

Merging of 2 sets of intervals

I have a union method setup to combine 2 sets of ordered intervals:
(define (union set1 set2)
(cond [(empty? set1) set2]
[(empty? set2) set1]
[(< (caar set1) (caar set2)) (cons (car set1) (union (cdr set1)
set2))]
[else (cons (car set2) (union set1
(cdr set2)))]))
Given 2 lists '((1 3) (5 10) (19 29)) and '((2 4) (17 25) (30 49)) they produce
'((1 3) (2 4) (5 10) (17 25) (19 29) (30 49)) with the code above.
But with the above implementation the overlapping intervals aren't being handled correctly. I am needing to merge the overlapping intervals to produce '((1 3) (2 4) (5 10) (17 29) (30 49)). How could I go about handling these interval merges so that there are no overlaps?
Assuming you're working with half-open intervals [from upto), Racket provides an interval-map module:
An interval-map is a mutable data structure that maps half-open intervals of exact integers to values. An interval-map is queried at a discrete point, and the result of the query is the value mapped to the interval containing the point.
The provided examples:
> (define r (make-interval-map))
> (interval-map-set! r 1 5 'apple)
> (interval-map-set! r 6 10 'pear)
> (interval-map-set! r 3 7 'banana)
> (dict-map r list)
'(((1 . 3) apple) ((3 . 7) banana) ((7 . 10) pear))
Using your example inputs '((1 3) (5 10) (19 29)) and '((2 4) (17 25) (30 49)):
#lang racket/base
(require data/interval-map
racket/list
racket/match
racket/dict)
(define im (make-interval-map))
;; Add your first set
(for ([x '((1 3) (5 10) (19 29))])
(interval-map-set! im (first x) (second x) #f))
;; Add your second set
(for ([x '((2 4) (17 25) (30 49))])
(interval-map-set! im (first x) (second x) #f))
;; The result
(map car (dict-map im list))
;; => '((1 . 2) (2 . 4) (5 . 10) (17 . 25) (25 . 29) (30 . 49))

Invalid function mod within lisp to recursively add sum positive integers that are multiples of certain numbers

I am trying to write function that sums all positive integers less than or
equal to 200 and are multiples of 6 and 7.
What I have is the following:
(defun sumFunction(current sum)
(if (/= current 200)
(if ((eq (mod current 6) 0) or (eq (mod current 7) 0))
(setf sum (+ sum current))
(sumFunction (+ current 1) sum)
)
(sumFunction ((+ current 1) sum)
)
)
It is giving me the following error:
Error handler called recursively (:INVALID-FUNCTION NIL IF ""
"~S is invalid as a function."
(EQ (MOD CURRENT 3) 0))
I am unsure of why there is any errors.
If I follow the logic it should return the result I need.
Any help is much appreciated!
Thanks
There are two syntax errors in your code, and there are also some other issues which do not match Lisp style. Please refer to the corrected code below.
(defun sumFunction(current sum)
(if (/= current 200)
(if (or (eq (mod current 6) 0) (eq (mod current 7) 0))
(sumFunction (+ current 1) (+ current sum))
(sumFunction (+ current 1) sum))
sum))
Here is the result.
(sumFunction 20 0)
;=> 5731

Resources