Different rules for cons arguments? - list

I'm new in Racket language and I bumped into an issue.
I'm now trying to implement Binary Search Tree using cons(list).
This is a simple BST I tried to make:
For this BST, if I convert this into Racket list, this can be one possibility:
'(6, (4, (), ()), (7, (), ())
To produce this format of list, I used this code:
(define x3 (cons 6 (cons (cons 4 (cons null (cons null null)))
(cons 7 (cons null (cons null null)))
And for this code, the result is below:
'(6 (4 () ()) 7 () ())
As you see, this is not what I wanted.
The second child node 7 () () is not inside the bracket, which means it doesn't exist as an list. It acts as individual 3 elements, not single list. So I changed a bit:
(define x2 (cons 6 (cons (cons (cons 4 (cons null (cons null null))) null)
(cons (cons 7 (cons null (cons null null))) null)
)
)
)
And for this 2nd code, the result is as following:
'(6 ((4 () ())) (7 () ()))
And this is not what I wanted either. The first child node ((4 () ())) now is inside and inside the list.
So I did the final try, and the code is like this:
(define x3 (cons 6 (cons (cons 4 (cons null (cons null null)))
(cons (cons 7 (cons null (cons null null))) null)
)
)
)
And the result looks like this:
'(6 (4 () ()) (7 () ()))
Now it works! The question is, why these things happen? I kind of realized that the rule is different between the last element of list and the other when cons is used, but after all, aren't they same kind of list?

First of all:
cons creates actually a cell, a cons cell.
You can append using cons several cons cells to each other.
(cons 'a 'b) ;; (a . b)
(cons 'c (cons 'a 'b)) ;; (c . (a . b))
The lisp notation says, ' . ( ' is ' ', so the last example simplifies to:
(c a . b)
What is a list?
Such cons cells or chain of cons cells with last element being ' . ()'.
In this case, you are allowed to make it invisible.
(cons 'c (cons 'a null)) ;; or
(cons 'c (cons 'a 'null)) ;; or
(cons 'c (cons 'a '())) ;; which are the same!
;; in common lisp even (cons 'c (cons 'a ())) in addition
Is thus simplified to:
(c a) ;; actually (c . (a . null))
These syntax simplification rules and the fact that cons takes only exact 2 arguments but you need 3 slots for the binary tree, makes the cons-constructs more complicated than the problem looks at the first sight.
Your BST should be expressed as lists:
(list 6 (list 4 null null) (list 7 null null))
which is already very complicated to express only with conses manually ...
(as explained by assefamaru)
As you see, list is an abstraction over the nesting of conses with the innermost cons - cell consing to a null, and more adapted to the simplication rules of the syntax. Thus much more brain-friendly.
But more elegantly, you should use structs (as explained here https://learningtogetolder.wordpress.com/2013/08/14/creating-a-binary-search-tree-in-racket/) by defining that each node expects a value and a left and a right node. Thereby, construction errors are made impossible.

When writing deep list-of-lists using cons, it can be very easy to lose track of where an inner list begins, or where it ends, etc. So if you are writing out a long list by hand, it might be easier to simply use list:
(list 6 (list 4 null null) (list 7 null null))
Otherwise, you can also build your cons list easily by writing it from the inside out. For example, in your BST, there are two leaf nodes with one root parent node. So you can start from the leaf nodes:
(define left (cons 4 (cons null (cons null null))))
(define right (cons 7 (cons null (cons null null))))
then the BST becomes:
(cons 6
(cons left
(cons right null)))
which is equivalent to:
(cons 6
(cons (cons 4 (cons null (cons null null)))
(cons (cons 7 (cons null (cons null null))) null)))

Related

Scheme procedure to replace elements in a list

I am trying to create a procedure in scheme which replaces a certain element in a list with another element
(define (replace var player list)
(if (null? list)
'()
(if (list? (car list))
(cons (replace var player (car list))
(replace var player (cdr list))
(if (equal? var (car list))
(cons player (replace var player (cdr list)))
(cons (car list) (replace var player (cdr list)))
))))
Currently the procedure does not replace any elements.
This is the input list
'(q w (e r (t x)) y u i (o (x)) p x a s d)
I would like to replace the 'x' elements in that list with 'y'.
This is the desired output
'(q w (e r (t y)) y u i (o (y)) p y a s d)
We have tried
(replace_by 'x 'y '(q w (e r (t x)) y u i (o (x)) p x a s d)
but it does not seem to be working
The posted code is missing one parenth at the end, and has a misplaced parenth. The first cons expression needs to be closed by a parenth:
(define (replace var player list)
(if (null? list)
'()
(if (list? (car list))
(cons (replace var player (car list))
(replace var player (cdr list)))
(if (equal? var (car list))
(cons player (replace var player (cdr list)))
(cons (car list) (replace var player (cdr list)))))))
After these corrections, the OP code works for nested lists where the item to be replaced is a non-list. But, it fails when the item to be replaced is a list. This is because list elements encountered in the input are never checked for equality against var. Note also that it is a bad idea to use list as a formal parameter in Scheme functions; this shadows the built-in list function.
Here is an implementation that will replace both atoms and lists in the input list. Before checking whether the input is an atom, the function checks for equality with old. If the old value is not equal? to the current head value, then the function checks whether the current head value is an atom. If it is, then that atom (which was not equal? to old) is consed onto the result of calling replace on the tail; note that empty lists are considered atoms ('() is both a list and an atom) and have already been handled at this stage. Otherwise, the current head is a non-empty list, and the function descends into both the head and the tail.
Here atom? is used to distinguish between non-empty lists and atoms, with '() being considered an atom. Some Schemes include a definition for atom?, but it is not in R5RS or R6RS Standard Scheme. You can define it yourself if needed:
(define (atom? x)
(not (pair? x)))
Or you could just use (not (pair? head)) in place of (atom? head) in the code below, which uses atom? because the name seems more descriptive. A let expression is used to reduce the number of calls to car and cdr, and to clarify the intent of the recursive calls to replace:
(define (replace old new xs)
(if (null? xs)
xs
(let ((head (car xs))
(tail (cdr xs)))
(cond ((equal? head old)
(cons new (replace old new tail)))
((atom? head)
(cons head (replace old new tail)))
(else
(cons (replace old new head)
(replace old new tail)))))))
Here are some sample interactions:
> (replace 'a 'x '(1 2 a 3 4 a))
(1 2 x 3 4 x)
> (replace 'a 'x '(1 2 a (3 4 a (5 a (a (a)) 6 a) ()) a))
(1 2 x (3 4 x (5 x (x (x)) 6 x) ()) x)
> (replace '() 'x '(1 2 a (3 4 a (5 a (a (a)) 6 a) ()) a))
(1 2 a (3 4 a (5 a (a (a)) 6 a) x) a)
> (replace '(5 a (a (a)) 6 a) 'x '(1 2 a (3 4 a (5 a (a (a)) 6 a) ()) a))
(1 2 a (3 4 a x ()) a)
> (replace '(5 a (a (a)) 6 a) '(x (x x)) '(1 2 a (3 4 a (5 a (a (a)) 6 a) ()) a))
(1 2 a (3 4 a (x (x x)) ()) a)

Insert element to circular list using scheme

I have a circular list, eg: #0=(1 2 3 4 . #0#).
What I want to do is to insert a new element (x) into this list so that the outcome is #0=(x 1 2 3 4 . #0#). I have been trying using this code (x is the circular list):
(define (insert! elm)
(let ((temp x))
(set-car! x elm)
(set-cdr! x temp)))
However, I think that set-cdr! is not working like I want it to. What am I missing here? Maybe I am way off?
The easiest way to prepend an element to a list is to modify the car of the list, and set the cdr of the list to a new cons whose car is the original first element of the list and whose cdr is the original tail of the list:
(define (prepend! x list) ; list = (a . (b ...))
(set-cdr! list (cons (car list) (cdr list))) ; list = (a . (a . (b ...)))
(set-car! list x)) ; list = (x . (a . (b ...)))
(let ((l (list 1 2 3)))
(prepend! 'x l)
(display l))
;=> (x 1 2 3)
Now, that will still work with circular lists, because the cons cell (i.e., pair) that is the beginning of the list remains the same, so the "final" cdr will still point back to object that is the beginning. To test this, though, we need some functions to create and sample from circular lists, since they're not included in the language (as far as I know).
(define (make-circular list)
(let loop ((tail list))
(cond
((null? (cdr tail))
(set-cdr! tail list)
list)
(else
(loop (cdr tail))))))
(define (take n list)
(if (= n 0)
'()
(cons (car list)
(take (- n 1)
(cdr list)))))
(display (take 10 (make-circular (list 1 2 3))))
;=> (1 2 3 1 2 3 1 2 3 1)
Now we can check what happens if we prepend to a circular list:
(let ((l (make-circular (list 1 2 3))))
(prepend! 'x l)
(display (take 15 l)))
;=> (x 1 2 3 x 1 2 3 x 1 2 3 x 1 2)
Since you're trying to prepend an element to a circular list, you need to do two things:
Insert a new cons cell at the front of the list containing the additional element. This is easy because you can just perform a simple (cons elm x).
You also need to modify the recursive portion of the circular list to point at the newly created cons cell, otherwise the circular portion will only include the old parts of the list.
To perform the latter, you need a way to figure out where the "end" of the circular list is. This doesn't actually exist, since the list is, of course, circular, but it can be determined by performing an eq? check on each element of the list until it finds an element equal to the head of the list.
Creating a helper function to do this, a simple implementation of insert! would look like this:
(define (find-cdr v lst)
(if (eq? v (cdr lst)) lst
(find-cdr v (cdr lst))))
(define (insert! elm)
(set! x (cons elm x))
(set-cdr! (find-cdr (cdr x) (cdr x)) x))

First 5 elements of a list in Scheme

I was wondering, if I was given a list such as:
(list 3 6 9 2 1 0 5 9)
and I wanted to produce only the first 5. i.e.: I want to produce:
(list 3 6 9 2 1)
How could I go about doing this. By the way, recursion is not allowed, and the language is intermediate student. Thanks :)
Actually a lis like (1 2 3 4) is a chain of pairs (1 . (2 . (3 . (4 . ())))). You cannot reuse the pairs since you need the 5th pair to point to () (null) instead of the rest of the pair chain. The only way to do this is to make a new pair for each element you'd like by using the same car elements in each.
(define (take lst cnt)
(if (zero? cnt) ; if you ask for zero element
'() ; then return empty list
(cons (car lst) ; else make a pair with first element
(take (cdr lst) ; and result from take with the rest of the list
(- cnt 1))))) ; with one less element than you originally asked for
If memory serves, in addition to car and cdr, Scheme supplies caar, caaar, caaaar and the equivalent repeated ds and the various combinations and permutations. So one solution would be:
(define x (list 3 6 9 2 1 0 5 9))
(list (car x) (cadr x) (caddr x) (cadddr x) (car (cddddr x)))
(and I'm sure that's why you were asked for the first five; there's no cdddddr — the teaching point was likely the permitted repetition of ds and as and the limit to which you can go with those)
I do not know why you would want to do this, but one way to avoid recursion is to unroll the loop:
(define (take1 xs) (cons (car xs) '()))
(define (take2 xs)
(cons (car xs) (take1 (cdr xs))))
(define (take3 xs)
(cons (car xs) (take2 (cdr xs))))
(define (take4 xs)
(cons (car xs) (take3 (cdr xs))))
(define (take5 xs)
(cons (car xs) (take4 (cdr xs))))

Multiplying numbers in a list (coordinate-wise) without using mapcar in Lisp

I'm having trouble with the output of my code, I think it's when I'm checking conditions for the null of my lists.
The question I am trying to complete is: Write a function vecmul that will take as inputs two simple lists of numbers. vecmul should multiply these lists coordinate-wise as one would multiply vectors. Assume the two lists are the same length. [For example, (vecmul '(2 3 4 5) '(1 4 5 2)) returns (2*1 3*4 4*5 5*2) or (2 12 20 10). You are not allowed to use mapcar for this function]
So far I have
(defun vecmul (list list2)
(cond ((null list) 0)
(t (cons (* (car list) (car list2))
(vecmul (cdr list) (cdr list2))))))
[170]> (setq l '(2 4 6))
(2 4 6)
[171]> (setq r '(1 3 5))
(1 3 5)
[172]> (vecmul l r)
(2 12 30 . 0)
I'm getting the correct numbers, it's just that the list is adding the "." and the "0" at the end of the list. I'm pretty sure it's because i'm not stopping the recursion right or not working the cond right. I'm just not entirely sure how to correct it.
You've got it almost right. However, you're terminating your list with 0, when the correct termination is nil. This code works:
(defun vecmul (list list2)
(cond ((null list) nil)
(t (cons (* (car list) (car list2)) (vecmul (cdr list) (cdr list2))))))
When you call (cons 1 2), the cons cell you get is written (1 . 2). the notation (1 2 3 4 5) is just shorthand for (1 . (2 . (3 . (4 . (5 . nil))))). If the cdr of the last cons cell is 6, not nil, then you get (1 . (2 . (3 . (4 . (5 . 6))))), which shortens to (1 2 3 4 5 . 6).
Neil Forrester answered your question.
Some more remarks. Use modern names in Lisp: first and rest.
(defun vecmul (list1 list2)
(cond ((null list1) nil)
(t (cons (* (first list1) (first list2))
(vecmul (rest list1) (rest list2))))))
If you have a simple true and false decision, IF might be better. Since list operations are involved, I would write it as the following and not use WHEN.
(defun vecmul (list1 list2)
(if (null list1)
nil
(cons (* (first list1) (first list2))
(vecmul (rest list1) (rest list2)))))
Best use a loop construct or mapping in real code. Recursion, as above, has a stack depth limit. A loop does not have that restriction.
(defun vecmul (list1 list2)
(loop for e1 in list1 and e2 in list2
collect (* e1 e2)))
or
(defun vecmul (list1 list2)
(mapcar #'* list1 list2))

Problem with list in Lisp

I am trying to write a simple procedure in Lisp to insert an element into binary search tree.
I represented the tree as a list:
the first element in the tree is the root
the second element is the left sub-tree
the third element is the right sub-tree
This is my code:
(define Insert
(lambda (x T)
(if (null? T)
(list x '() '())
(if (> x (car T))
(list (car T)
(cadr T)
(Insert x (list (caddr T))))
(list (car T)
(Insert x (cadr T))
(list (caddr T)))))))
When I call the procedure like this: (Insert 2 '(4 '(2 '() '() ) '())), I get a problem with ">" because the second argument isn't a real number, but I don't know why.
The exception:
>: expects type <real number> as 2nd argument, given: quote; other arguments were: 2
However, when I call the procedure like this: (Insert 2 ( list 4 (list 2 '() '() ) '())),
it works successfully.
Why?
I know that '(1 '() '()) and (list 1 '() '()) are equals, aren't they?
No, quote and list are not the same at all. The meaning of 'foo is (quote foo).
'(a b c) is exactly (quote (a b c)), that is, a list literal (the quote operator prevents the list from being evaluated). It is comparable to "a b c", which is a string literal or 5, which is a number literal. Operations that modify literals have undefined effects, as you may recognize immediately when you see some nonsense like (setf 3 4).
(list a b c), on the other hand, creates ("conses") a new list from the values of a, b, and c.
I am sure that if you clear up your confusion about quote and list, you will be able to correct your code.
'(1 '()) is equivalent to (list 1 (list 'quote nil)). I suspect that if you drop the "internal" quote characters, you will be fine.
So, the quoted expression that generates an expression that is equal to (list 1 '() '()) is '(1 () ()).