Finding the depth of a list using (constrained) Racket - list

Another question of logic, the task is to find the depth of a list, for example: given a list of (A B (C D (E))) it should somehow indicate that the depth is 2 (or 3 if you include the base list). I am restricted to a set of common Racket functions of which I will list below. Where I am at I can iterate through the list but end up halting at the first sub-list, i.e: (A (B (C)) (D (E (F)))) comes out as only 2.
Here is the list of functions available:
cons, car, cdr, define, quote, if, cond, else
Basic forms of arithmetic (+, -, *, /)
Very basic tests (null?, list?, eq?, numeric comparisons)
Here is my definition so far, I would really appreciate if someone could just shift me in the right direction.
(define (len l) (if (null? l) 0 (+ 1 (len (cdr l)))))
(define A '(A (B) (C (D))))
(define (depth l) (cond
[(null? l) '()]
[(list? (car l)) (cons (car l) (depth (car l)))]
[else (depth (cdr l))]
))
(depth A)
(len (depth A))

Here is my definition in Common Lisp
(defun list-depth (list &optional (depth 0))
(cond ((null list) depth)
((atom (first list)) (list-depth (rest list) depth))
(t (max (list-depth (first list) (1+ depth))
(list-depth (rest list) depth)))))
I don't have Racket installed on this computer, so here is an untested translation to Scheme/Racket:
(define (list-depth lst depth)
(cond ((null? lst) depth)
((not (list? (car lst)) (list-depth (cdr list) depth))
(else (max (list-depth (car lst) (+ 1 depth))
(list-depth (cdr lst) depth)))))
Logic is as follows:
If the list is empty, return current depth.
If the car of the list is atom (not list), it won't increase the depth, find the depth of the rest (cdr) of the list.
Otherwise, the depth is going to be the maximum between the +1 depth of car (remember, it is the list now) and the depth of the cdr of the list. Notice increase of the depth for car and not for cdr.
Pre-defined procedures used: +, max, null?, list?, car, cdr, not.

In my answer here, lists start with a depth of 0 and increase by 1 for each level of nesting. If you'd like for them to start with a depth of 1, you can change (y 0) to (y 1) in the list-depth procedure
This can be implemented with a straightforward fold
(define (list-depth xs (y 0))
(foldl (λ (x z)
(if (list? x)
(max z (list-depth x (+ 1 y)))
(max z y)))
y
xs))
foldl has a simple implementation of
(define (foldl f y xs)
(if (null? xs)
y
(foldl f (f (car xs) y) (cdr xs))))
Here's some outputs
(list-depth '()) ; ⇒ 0
(list-depth '(A)) ; ⇒ 0
(list-depth '(A (B))) ; ⇒ 1
(list-depth '(A (B (C)))) ; ⇒ 2
(list-depth '(A (B (C (D (E)))) (B (C)) (B))) ; ⇒ 4
If you don't want to use the fold abstraction, you can expand the fold within list-depth to
;; THIS CODE IS BROKEN, DO NOT USE
;; #mobiuseng found bugs
(define (list-depth xs (y 0))
(cond
[(null? xs) y]
[(list? (car xs))
(max y (list-depth (car xs) (+ 1 y)))]
[else
(max y (list-depth (cdr xs) y))]))
Both result in the same output, but in this implementation, the two concepts of folding and max are tangled together. Seeing the guts of the fold makes it much harder to read this answer compared to the first one.
The guts of the fold made it easy for bugs to hide in this last snippet. I can't suggest writing this way in the first place, so I'm not going to bother spending effort to fix it.

Every list is built of a current element, under its car, and the rest of the list, under the cdr.
The depth of the list is the same as depth of the rest of the list, if that's the deepest.
The depth of the list is one more than the depth of its car, if that's the deepest.
So,
(define (depth lst)
(define a-depth (+ 1 (depth (car lst))))
(define d-depth (depth (cdr lst)))
(if (< ..... ) .....
; or else
...... ))
And of course, don't forget to handle the case when the list is empty, or an atom (not a pair — you can't call car or cdr with a non-pair argument, it would cause an error if you did):
The depth of an empty list is zero.
The depth of an atom is zero.

Related

Why does this arithmetic code return lists?

I'm currently working my way through exercise 3.17 of SICP. I know that I'm messing it up and I intend to fix that later. I will not link the exercise, as it is not relevant. This was one of my attempts:
#lang sicp
(define (count-pairs x)
(define encountered '())
(define counter 0)
(define (loop x)
(set! counter (+
(cond
((null? x) 0)
((not (pair? x)) 0)
((null? encountered) (set! encountered (list (car x))) 1)
((eq? (car x) (car encountered)) 0)
(else 1))
counter))
(if (not (pair? x)) counter (begin (loop (car x))
loop (cdr x))))
(loop x))
(count-pairs (list 'a 'b 'c))
(define second (cons 'a 'b))
(define third (cons 'a 'b))
(define first (cons second third))
(set-car! third second)
(count-pairs first)
(define 3rd (cons 'a 'b))
(define 2nd (cons 3rd 3rd))
(define 1st (cons 2nd 2nd))
(count-pairs 1st)
To my shock, this returned:
(b c)
((a . b) . b)
((a . b) a . b)
How is this possible? I know that this code isn't even close to doing as intended, but as far as I can see it should only do arithmetic and therefore return numbers. How is it possible for this code to return list structures?
Get a new IDE. Stack Overflow's syntax highlighting makes this a dead giveaway.
(begin (loop (car x))
loop (cdr x))))

When using recursion, how can I append or concatenate multiple pairs into a single, longer list?

This is a homework problem, so please point in a good direction w/o giving a solution.
Basically, within Scheme, I am trying to build a multi-bit adder starting with logic gates.
Thanks for reading/helping.
An example I am running is adding 101001 and 011101 with a 1 carry in.
I feel like I had a list and be appending throughout? But if this is the correct step, I cannot get this to work.
(define l-and (lambda (x y) (if (and (equal? x 1) (equal? y 1)) 1 0)))
(define l-or (lambda (x y) (if (or (equal? x 1) (equal? y 1)) 1 0)))
(define l-xor (lambda (x y) (if (or (equal? (l-and x y) 1) (and (equal? x 0) (equal? y 0)) ) 0 1)))
(define l-not (lambda (x) (if (equal? x 0) 1 0)))
(define fulladdr (lambda (x y z)
(cons
(l-xor (l-xor x y) z)
(l-or (l-and x y) (l-and z (l-xor x y)))
)
))
(define (removelast lis)
;(display (reverse(cdr (reverse lis)))) For debugging
(if (null? (cdr lis))
'()
(reverse(cdr (reverse lis)
))))
(define (last-element lis)
;(display (car(reverse lis))) For debugging
(if (null? (cdr lis))
'() (car(reverse lis))
))
(define n-bit-addr (lambda (l1 l2 x)
(if (or (null? l1) (null? l2))
'()
(let ((carry (cdr (fulladdr (last-element l1) (last-element l2) x))))
(let (( sum (car (fulladdr (last-element l1) (last-element l2) x))))
;(display carry) For debugging
(cons
(fulladdr (last-element l1) (last-element l2) x)
(n-bit-addr (removelast l1) (removelast l2) carry)
)))))
When I run my code with this example, a couple others, I get the correct output, kind of: ((1 . 1) (1 . 0) (1 . 0) (0 . 1) (0 . 1) (0 . 1))
I am trying to figure out how to format this so my output would be (111000.1). Basically (Binary . FinalCarry)
Here are some observations. An adder uses carry so you'll need to operate on leas significant digits to most significant.
A list is created from end to beginning. eg. (1 2) can be created (cons 1 (cons 2 '())) which means the second argument (cons 2 '()) needs to be finished.
I guess your arguments are binary digits in a list like (1 0 1 0) as 10. If you had a helper or a named let you could have the two arguments so far, the carry and sum as parameters so that you can use them as state. Also you are calling fulladdr with the same arguments 3 times. Here is what I think you should do:
(define (n-bit-addr l1 l2)
(helper (reverse l1) (reverse l2) 0 '()))
This defeats the purpose of getting and removing the "last" element and rather fetching and removing the first, which is much easier to do in Scheme.
Now here is the rest. I've abstracted some of the challenged out eg. what happens when you do (n-bit-addr '(1 1) '(1 1 1 0)) is magically worked around by not using car and cdr directly.
(define (helper l1 l2 carry acc)
;; actual implementation of n-bit-addr
(if (finished? l1 l2)
(finish acc carry)
(let* ((res (fulladdr (car0 l1) (car0 l2) carry))
(sum (car res))
(carry (cdr res)))
(helper (cdr* l1) <??> <??> <??>))))
(define (car0 lst)
;; returns 0 if lst is null? (car lst) otherwise
)
(define (cdr* lst)
;; return '() if lst is null? (cdr lst) otherwise
)
(define (finished? l1 l2)
;; return #t is both are null?
)
(define (finish sum carry)
;; return whatever structure one would want with the last result
;; I would imagine carry could be the the highest bit if it's set. thus
;; (n-bit-addr '(1) '(1)) ; ==> (1 0)
)
Now if (1 0 1 0) is not satisfactory you should make number->logic and logic->number that transform (1 0 1 0) to #b1010. This can easily be done with list iteration and arithmetic. Since you want to know how to do lists to number I'll do the other way:
(define (number->logic n)
(let loop ((n n) (acc '()))
(cond ((not (zero? n)) (loop (quotient n 2) (cons (remainder n 2) acc)))
((null? acc) '(0))
(else acc))))
(number->logic #b1010) ; ==> (1 0 1 0)
Note that #b1010 is just a fancy way of writing 10
(number->logic 10) ; ==> (1 0 1 0)
The other way around would be to start the accumulator at 0 and for each element in the list in order multiply the accumulator with 2 and add the bit. When the list is null? the accumulator would be the number.
(logic->number '(1 0 1 0)) ; ==> 10
I remember building adders with nand gates at School, but I haven't done so in programming. You should try it.

Add or remove element in the middle of list (Scheme)

Is it possible to add or remove elements in the middle of a linked list in Scheme? I can't seem to think of a way doing this with car/cdr/cons, but I reccon there must be a way to this.
If I have a list '(1 3 5 6), and I need to put in 4 between 5 and 6 for example, is this doable?
Adding an element at a given position was done in a previous answer. Removing an element at a given position is similar:
(define (delete-at k lst)
(cond ((null? lst)
'())
((zero? k)
(cdr lst))
(else
(cons (car lst)
(delete-at (sub1 k) (cdr lst))))))
Here are two versions:
; list-insert : value index list -> list
; return list where the ith element is x
(define (list-insert x i xs)
(if (= i 0)
(cons x xs)
(cons (first xs) (list-insert x (- i 1) (rest xs)))))
(define (list-insert/version2 x i xs)
(define-values (before after) (split-at xs i))
(append before (list x) after))
(list-insert/version2 'x 2 '(a b c d))
(list-insert 'x 2 '(a b c d))
Both versions will allocate a new list. For large lists it will become inefficient.

Depth of list in scheme

I'm trying to write a program in scheme that will find the maximum depth of a list. My code so far is:
(define (depth l)
(define (helper l count)
( cond
((null? l) count)
((not(list? (car l))) (helper (cdr l) count))
(else (helper (car l) (+ count 1)) )
)
)
(helper l 1)
)
It works for lists of this type (depth '(1 2 3 (2))) -> 2, but obviously not for list of the type (depth '( (2) ((3))) -> 3. The problem is that when I first encounter a list, I automatically jump to it increment the count and call it recursively again, ignoring the other elements of the list. I want to fix this problem and I thought of adding another variable temp which to hold the current count for each element in the list and check if it is bigger than count and if it is true I set! count to temp, but again I have a problem with the recursion. My other idea was to use another list in which to append count on every step and find the maximum value in that list, but I couldn't realize that too. Any ideas how to do this problem?
Here's an implementation using map:
(define (max-depth l)
(define (helper depth el)
(cond
[(null? el) (add1 depth)]
[(list? el)
(apply max
(map (curry helper (add1 depth))
el))]
[else depth]))
(helper 0 l))
While I think this implementation is fairly elegant, it admittedly is not tail-recursive.
Here is a slightly more complex, breadth-first tail-recursive implementation:
(define (max-depth l)
(define (helper depth els)
(define remaining (filter list? els))
(if (zero? (length remaining))
depth
(helper (add1 depth) (apply append remaining))))
(helper 1 l))

Multiplying Elements in a List Containing Pairs

I'm trying to write a code (function) using Scheme that:
Takes a list of any size as a parameter
Multiplies every number of the list together
Symbols should be skipped over
Values inside pairs should be included in multiplication
In other words, results should be as follows:
> (mult '(1 2 3))
6
> (mult '(1 2 x 3 4))
24
> (mult '(1 2 z (3 y 4)))
24 (mine gives me 2)
My code allows me to skip over the symbols and multiply everything. However, once I include a pair inside the list, it acts as though it isn't a number, therefore acting like it doesn't exist. Here's my code:
(define mult
(lambda (x)
(if (null? x)
1
(if(number? (car x))
(* (car x) (mult (cdr x)))
(mult(cdr x))))))
I've tried to use append when it finds a pair, but clearly I did it wrong... Any help on how I could get it to include the values inside a pair would be much appreciated.
i.e. '(1 2 y (3 z 4) = 1 * 2 * 3 * 4
You are nearly there, just missing the list? test:
(define (mult lst)
(if (null? lst)
1
(let ((ca (car lst)))
(cond
((number? ca) (* ca (mult (cdr lst))))
((list? ca) (* (mult ca) (mult (cdr lst))))
(else (mult (cdr lst)))))))
EDIT
He're an equivalent version without let:
(define (mult lst)
(cond
((null? lst) 1)
((number? (car lst)) (* (car lst) (mult (cdr lst))))
((cons? (car lst)) (* (mult (car lst)) (mult (cdr lst))))
(else (mult (cdr lst)))))
As you see, (car lst) is likely to be evaluated more than once, so I used let in the first version to avoid this.
It is a slightly advanced technique but this problem can easily be formulated as a tail recursive algorithm.
(define (mult lst)
(let multiplying ((lst lst) (r 1)) ; r is the multiplicative identity...
(if (null? lst)
r
(let ((next (car lst))
(rest (cdr lst)))
(multiplying rest (cond ((number? next) (* next r))
((list? next) (* (mult next) r))
(else r)))))))
> (mult '(1 2 3 a b (((((10)))))))
60
Using tail recursion has performance implications but, admittedly, it is not the first thing to learn - recursion is. However, in this case, because lists are often very long, avoiding a stack frame for each list element can be a dramatic savings; using tail calls avoids the stack frame.