Help explaining how `cons` in Scheme work? - scheme

This is the function that removes the last element of the list.
(define (remove-last ll)
(if (null? (cdr ll))
'()
(cons (car ll) (remove-last (cdr ll)))))
So from my understanding if we cons a list (eg. a b c with an empty list, i.e. '(), we should get
a b c. However, testing in interaction windows (DrScheme), the result was:
If (cons '() '(a b c))
(() a b c)
If (cons '(a b c) '())
((a b c))
I'm like what the heck :(!
Then I came back to my problem, remove all elements which have adjacent duplicate. For example,
(a b a a c c) would be (a b).
(define (remove-dup lst)
(cond ((null? lst) '())
((null? (cdr lst)) (car lst))
((equal? (car lst) (car (cdr lst))) (remove-dup (cdr (cdr lst))))
(else (cons (car lst) (car (cdr lst))))
)
)
It was not correct, however I realize the answer have a . between a b. How could this happen?
`(a . b)`
There was only one call to cons in my code above, I couldn't see which part could generate this .. Any idea?
Thanks,

cons build pairs, not lists. Lisp interpreters uses a 'dot' to visually separate the elements in the pair. So (cons 1 2) will print (1 . 2). car and cdr respectively return the first and second elements of a pair. Lists are built on top of pairs. If the cdr of a pair points to another pair, that sequence is treated as a list. The cdr of the last pair will point to a special object called null (represented by '()) and this tells the interpreter that it has reached the end of the list. For example, the list '(a b c) is constructed by evaluating the following expression:
> (cons 'a (cons 'b (cons 'c '())))
(a b c)
The list procedure provides a shortcut for creating lists:
> (list 'a 'b 'c)
(a b c)
The expression (cons '(a b c) '()) creates a pair whose first element is a list.
Your remove-dup procedure is creating a pair at the else clause. Instead, it should create a list by recursively calling remove-dup and putting the result as the second element of the pair. I have cleaned up the procedure a bit:
(define (remove-dup lst)
(if (>= (length lst) 2)
(if (eq? (car lst) (cadr lst))
(cons (car lst) (remove-dup (cddr lst)))
(cons (car lst) (remove-dup (cdr lst))))
lst))
Tests:
> (remove-dup '(a b c))
(a b c)
> (remove-dup '(a a b c))
(a b c)
> (remove-dup '(a a b b c c))
(a b c)
Also see section 2.2 (Hierarchical Data and the Closure Property) in SICP.
For completeness, here is a version of remove-dup that removes all identical adjacent elements:
(define (remove-dup lst)
(if (>= (length lst) 2)
(let loop ((f (car lst)) (r (cdr lst)))
(cond ((and (not (null? r))(eq? f (car r)))
(loop f (cdr r)))
(else
(cons (car lst) (remove-dup r)))))
lst))

Here in pseudocode:
class Pair {
Object left,
Object right}.
function cons(Object left, Object right) {return new Pair(left, right)};
So,
1. cons('A,'B) => Pair('A,'B)
2. cons('A,NIL) => Pair('A,NIL)
3. cons(NIL,'A) => Pair(NIL,'A)
4. cons('A,cons('B,NIL)) => Pair('A, Pair('B,NIL))
5. cons(cons('A 'B),NIL)) => Pair(Pair('A,'B),NIL)
Let's see lefts and rights in all cases:
1. 'A and 'B are atoms, and whole Pair is not a list, so (const 'a 'b) gives (a . b) in scheme
2. NIL is an empty list and 'A is an atom, (cons 'a '()) gives list (a)
3. NIL and 'A as above, but as left is list(!), (cons '() 'a) gives pair (() . a)
4. Easy case, we have proper list here (a b).
5. Proper list, head is pair (a . b), tail is empty.
Hope, you got the idea.
Regarding your function. You working on LIST but construct PAIRS.
Lists are pairs (of pairs), but not all pairs are lists! To be list pair have to have NIL as tail.
(a b) pair & list
(a . b) pair not list
Despite cons, your function has errors, it just don't work on '(a b a a c c d). As this is not related to your question, I will not post fix for this here.

Related

How to rotate a list that goes in the right direction

I want to be able to make my list go one step to the right. Here's my example code that makes it go one step to the left.
(define (rotate-L lst) (append (cdr lst) (list (car lst))))
(rotate-L '(a b c))
(b c a)
I'm having trouble understanding why when I make it backward, i get an error
(define (rotate-L lst) (append (car lst) (list (cdr lst))))
(rotate-L '(a b c))
SchemeError: argument 0 of append has wrong type (string)
Current Eval Stack:
0: (rotate-L (quote (a b c)))
(define rotr
(lambda (l)
(if (null? l)
l
((lambda (s) (s s l cons))
(lambda (s l c)
(if (null? (cdr l))
(c (car l) '())
(s s (cdr l)
(lambda (f r)
(c f (cons (car l) r))))))))))
(define rotl
(lambda (l0)
(if (null? l0)
l0
((lambda (s) (s s (cdr l0) (lambda (r) r)))
(lambda (s l c)
(if (null? l)
(c (list (car l0)))
(s s (cdr l)
(lambda (r)
(c (cons (car l) r))))))))))
Here is a test:
(rotr '())
(rotr '(a))
(rotr '(a b))
(rotr '(a b c))
(rotl '())
(rotl '(a))
(rotl '(a b))
(rotl '(a b c))
whose output is so:
1 ]=> (rotr '())
;Value: ()
1 ]=> (rotr '(a))
;Value: (a)
1 ]=> (rotr '(a b))
;Value: (b a)
1 ]=> (rotr '(a b c))
;Value: (c a b)
1 ]=> (rotl '())
;Value: ()
1 ]=> (rotl '(a))
;Value: (a)
1 ]=> (rotl '(a b))
;Value: (b a)
1 ]=> (rotl '(a b c))
;Value: (b c a)
It's worth remembering what lists look like as structures made of conses:
(1 2 3 4) looks like this, for instance
So pretty obviously (car '(1 2 3 4)) is a number, not a list, and so (append (car '(1 2 3 4)) ...) is not going to work, because append wants its arguments to be lists. But even if you fix this to be correct, you're not doing what you think:
(define (not-rotating lst)
(append (list (car lst)) (cdr lst)))
This simply takes the first element of the list, makes a single-element list from it, and appends the rest of the list to it. Well, you could write this more easily:
(define (not-rotating lst)
(cons (car lst) (cdr list)))
and it should be clear that this is doing nothing at all useful.
To rotate the list 'right' you need to:
find the last element of the list;
construct a list which is all of the original list except for that element;
and glue the last element onto the start of that list.
The only way to find the last element of the list is to walk along the list until you get to it. And you also need to make a copy of all the elements of the list but the last one, which also means walking down the list. It is natural to do these two operations at the same time:
walk down the list, building up a copy of it;
when you get to the last element, attach it to the start of the copy.
Here is a terrible way of doing this:
(define (rotate-r/terrible lst)
(let rrl ((tail lst)
(building '()))
(if (null? (cdr tail))
;; we've got to the end
(cons (car tail) building)
(rrl (cdr tail)
(append building (list (car tail)))))))
This is terrible because at each step it appends the current element to the end of the list it is building. That's terrible for not one but two reasons:
appending two lists takes time proportional to the length of the first list;
appending two lists requires a complete copy of the first list to be made.
That makes this both quadratic in the length of the list, which is terrible, and also very 'consy' – it allocates lots of ephemeral storage. But it does work.
So: there is, not surprisingly a better way of doing this: a way which is both linear and makes no more than two copies of the list. I'm not going to give it here, but it's surprisingly close to the above terrible solution. Two hints:
what is the natural way to accumulate elements into a list? is it at the start, or at the end of a list?
how do you turn the list you accumulated like that into the list you want?

cons* in scheme - how to implement

I tried to implement the cons* (https://scheme.com/tspl4/objects.html#./objects:s44).
Examples:
(cons* '()) -> ()
(cons* '(a b)) -> (a b)
(cons* 'a 'b 'c) -> (a b . c)
(cons* 'a 'b '(c d)) -> (a b c d)
this is what I did do far but I don't know how to replace the ?? to make the third example (the dot notion) work
(define cons*
(lambda x
(if
(null? x)
x
(if (list? (car (reverse x)))
(fold-right cons (car (reverse x)) (reverse (cdr (reverse x))))
???
)
)
)
)
Here's a lo-fi way using lambda -
(define cons*
(lambda l
(cond ((null? l) null)
((null? (cdr l)) (car l))
(else (cons (car l) (apply cons* (cdr l)))))))
Here's a way you can do it using match (Racket)
(define (cons* . l)
(match l
((list) null) ; empty list
((list a) a) ; singleton list
((list a b ...) (cons a (apply cons* b))))) ; two or elements
Often times patterns and order can be rearranged and still produce correct programs. It all depends on how you're thinking about the problem -
(define (cons* . l)
(match l
((list a) a) ; one element
((list a b) (cons a b)) ; two elements
((list a b ...) (cons a (apply cons* b))))) ; more
Or sugar it up with define/match -
(define/match (cons* . l)
[((list)) null]
[((list a)) a]
[((list a b ...)) (cons a (apply cons* b))])
All four variants produce the expected output -
(cons* '())
(cons* '(a b))
(cons* 'a 'b 'c)
(cons* 'a 'b '(c d))
'()
'(a b)
'(a b . c)
'(a b c d)
Personally, I'd use a macro instead of a function to transform a cons* into a series of cons calls:
(define-syntax cons*
(syntax-rules ()
((_ arg) arg)
((_ arg1 rest ...) (cons arg1 (cons* rest ...)))))
(define (writeln x)
(write x)
(newline))
(writeln (cons* '())) ;; -> '()
(writeln (cons* '(a b))) ;; -> '(a b)
(writeln (cons* 'a 'b 'c)) ;; -> (cons 'a (cons 'b 'c)) -> '(a b . c)
(writeln (cons* 'a 'b '(c d))) ;; -> (cons 'a (cons 'b '(c d))) -> '(a b c d)
A Simple Procedure
I think that you are making this more complicated than it needs to be. It seems best not to use lambda x here, since that would allow calls like (cons*) with no arguments. Instead, I would use (x . xs), and I would even just use the define syntax:
(define (cons* x . xs)
(if (null? xs)
x
(cons x (apply cons*
(car xs)
(cdr xs)))))
If there is only one argument to cons*, then xs is empty, i.e., (null? xs) is true, and that single argument x should be returned. Otherwise you should cons the first argument to the result of calling cons* again, with the first element of xs as the first argument, followed by the remaining arguments from xs. The trick here is that (cdr xs) returns a list, which will itself be put into a list thanks to the (x . xs) syntax. This is the reason for using apply, which will apply cons* to the arguments in the list.
This works for all of the test cases:
> (cons* '())
()
> (cons* '(a b))
(a b)
> (cons* 'a 'b 'c)
(a b . c)
> (cons* 'a 'b '(c d))
(a b c d)
Using Mutation
Taking a closer look at what a proper list really is suggests another approach to solving the problem. Consider a list like (a b c d). This is really a chain of cons cells that look like this:
(a . (b . (c . (d . ()))))
We would like to transform this list to an improper, or dotted, list:
(a . (b . (c . (d . ())))) --> (a . (b . (c . d)))
This transformed list is equivalent to (abc.d), which is what we would like the call to (cons* 'a 'b 'c 'd) to return.
We could mutate the proper list to an improper list by setting the cdr of the next-to-last pair to the car of the last pair; that is, by setting the cdr of (c . (d .()) to d. We can use the list-tail procedure to get at the next-to-last pair, list-ref to get at the car of the last pair, and set-cdr! to set the cdr of the next-to-last pair to the new value. After this, the list is no longer terminated by an empty list (unless the car of the final pair is itself an empty list!).
Here is a procedure proper->improper! that mutates a proper list to an improper list. Note that the input must be a proper list to avoid an error. If the input list contains only a single element, then that element is simply returned and no mutation takes place.
(define (proper->improper! xs)
(cond ((null? (cdr xs))
(car xs))
(else
(set-cdr! (list-tail xs (- (length xs) 2))
(list-ref xs (- (length xs) 1)))
xs)))
Now cons* can be defined simply in terms of proper->improper!:
(define (cons* . xs)
(proper->improper! xs))
Here, the arguments to cons* are packed up into a fresh list and passed to proper->improper! which effectively removes the terminal empty list from its input, returning a chain of pairs whose last cdr is the last argument to cons*; or if only one argument is provided, that argument is returned. This works just like the other solution:
> (cons* '())
()
> (cons* 'a)
a
> (cons* 'a 'b 'c 'd)
(a b c . d)
> (cons* 'a 'b '(c d))
(a b c d)
Real Life
In real life, at least in Chez Scheme, cons* is not implemented like any of these solutions, or even in Scheme at all. Instead Chez opted to make cons* a primitive procedure, implemented in C (I believe).

Lists traversal in Scheme

myList is a list with elements both as symbols or lists of the same type of myList.
For example: myList = '(a b (a d c) d ()) , etc.
I want to write a function in Scheme which would just traverse it (eventually I will replace the symbols with other values).
I wrote this function:
(define traversal (lambda (myList)
(if (null? myList) '()
(if (and (list? (car myList)) (not (null? (car myList))))
(list (traversal (car myList)) (traversal (cdr myList)))
; else if car is an empty list
(if (null? (car myList))
(list (traversal (cdr myList)))
; else car is a symbol
(append (list (car myList)) (traversal (cdr myList))))))))
It gives correct results for some configuration of myList, but definitely it is not the one.
For example,
(display (traversal '((f) h (r t b) (x m b m y) b (c (d)))))
adds additional paranthesis which I don't need.
What would be a correct way to display such a list?
You're testing null? in so many places, where one test is generally enough.
You rarely use list in these traversals, but simply cons.
Also, append is best avoided, and not needed here.
Repetitive use of (car ...) is optimised with a let form.
The simplified form of your code would be:
(define traversal
(lambda (myList)
(if (null? myList)
'()
(let ((c (car myList)))
(cons (if (list? c) (traversal c) c)
(traversal (cdr myList)))))))
EDIT
While this procedure works well for proper lists, it doesn't correctly work for improper lists (although it appears to). The following is a more general approach that works for every kind of S-expression, including proper lists, and I recommend this over the previous code:
(define traversal
(lambda (sexp)
(cond
((null? sexp) '())
((pair? sexp) (cons (traversal (car sexp))
(traversal (cdr sexp))))
(else sexp))))
You are close to the solution. Here are a few hints:
Instead of nested ifs try using the cond form, it is more readable.
The expression (and (list? (car myList)) (not (null? (car myList)))) is correct, but you may use (pair? (car myList)) which is shorter and does almost the same thing.
traversal should return a list but using list with list arguments here
(list (traversal (car myList)) (traversal (cdr myList)))
will return a list of lists. E.g. (list '(a) '(b)) will return ((a) (b)) instead of (a b). In these cases you should use append (append '(a) '(b)) -> (a b).
If a value is not a list but you want to add it to an existing list, use the cons procedure.
(cons 'a '(b c)) -> (a b c).

Scheme collecting similar items in a list and finding most common item in a list [duplicate]

This question already has answers here:
Count occurrence of element in a list in Scheme?
(4 answers)
Closed 8 years ago.
I want to make a function that occurs how many times an element occurs in a list. For example in the list: '(a b c b b c c a) I want it to return a nested list with:
'((a 2) (b 3) (c 3))
I know the function will look sort of like this:
(define collect-similar
(lambda (elm ls)
(cond
[(null? ls) '()]
[(equal? elm (car ls))]
I know that I need to continue checking through the list until it arrives back at the base case of the null list and I can check the rest of the list by using cadr. But I'm not too sure on how to get the value and how to make it return the nested list.
The next function I'm trying to write finds the most common element in the list. For example running the function on the list '(a a a a a b c) will simply return a. I know I can make use of the collect-similar function and find which number is the highest.
This has been asked before, just adapt one of #ChrisJester-Young's bagify implementations. For example:
(define (collect-similar lst) ; a slightly modified `bagify`
(hash->list
(foldl (lambda (key ht)
(hash-update ht key add1 0))
'#hash()
lst)))
(collect-similar '(a b c b b c c a))
=> '((a . 2) (b . 3) (c . 3))
With collect-similar in place, it's simple to find the most common element:
(define (most-common lst)
(let loop ((alst (collect-similar lst)) ; use previous procedure
(maxv '(#f . -inf.0)))
(cond ((null? alst) (car maxv))
((> (cdar alst) (cdr maxv))
(loop (cdr alst) (car alst)))
(else
(loop (cdr alst) maxv)))))
(most-common '(a a a a a b c))
=> 'a

DR Racket Flip a list of letter

this is a recursive function flip in Scheme which accepts a list of atoms of arbitrary length as its only argument and returns that list with adjacent elements flipped. In other words, the
function alternates elements of a list (i.e., given a list [a1,a2,a3,a4,a5,a6...,an] as an argument,
produce [a2,a1,a4,a3,a6,a5,...]). If n is odd, an remains at the end of the resulting list. not using any auxiliary functions.
here is my sample
> (flip '())
()
> (flip '(a))
(a)
> (flip '(a b))
(b a)
> (flip '(a b c d))
(b a d c)
> (flip '(a b c d e))
(b a d c e)
This is homework, so I can't give you a straight answer. Here's the general idea of the solution, fill-in the blanks:
(define (flip lst)
(cond ((null? lst) ; The list is empty:
<???>) ; return the empty list.
((null? (cdr lst)) ; The list has a single element:
<???>) ; return a list with the single element.
(else ; The list has at least two elements:
(cons <???> ; cons the second element ...
(cons <???> ; ... to the first element ...
(flip <???>)))))) ; ... and advance two elements at once.
(define (flip lst)
(cond ((null? lst)
null)
((null? (cdr lst))
lst)
(else
(cons (car (cdr lst))
(cons (car lst)
(flip (cdr (cdr lst))))))))

Resources