Scheme explanation - cdr and car - scheme

I've got this example :
(apply + 2 (cdadr '(1 ((2 . 3) 4))))
This returns 6? Why is (cdadr '(1 ((2 . 3) 4))) 4??
I don't get it.Shouldn't it be 3?

The result is the list '(4), not the number 4.
You have a list with two elements, where 1 is the first element, and the list ((2 . 3) 4) is the second element.
In other words, the cdr of the list is (cons ((2 . 3) 4)) '()), or (((2 . 3) 4)).
> (cdr '(1 ((2 . 3) 4)))
'(((2 . 3) 4))
This is a list with one element - the list ((2 . 3) 4) - which is of course the car.
> (car (cdr '(1 ((2 . 3) 4))))
'((2 . 3) 4)
and, finally,
> (cdr (car (cdr '(1 ((2 . 3) 4)))))
'(4)

A list (a b c) is short for (a . (b . (c . ()))).
Therefore '(1 ((2 . 3) 4))) is short for '(1 ((2 . 3) . (4 . ())) . ()).
To make sure, we test it in the REPL:
> ''(1 ((2 . 3) . (4 . ())) . ())
'(1 ((2 . 3)) 4)
cdadr is short for (cdr (car (cdr _))).
Here car extract the first part of a pair (car '(a . d)) = a
and cdr extract the second part of a pair (cdr '(a . d)) = d
Let's see what happpens:
> (cdr '(1 ((2 . 3) . (4 . ())) . ()))
'(((2 . 3) 4))
> (car (cdr '(1 ((2 . 3) . (4 . ())) . ())))
'((2 . 3) 4)
> (cdr (car (cdr '(1 ((2 . 3) . (4 . ())) . ()))))
'(4)
> (apply + 2 '(4))
6
Note that ((2 . 3) 4) is the same as ((2 . 3) . (4 . ())) and that the cdr of this (4 .()) aka (4).

Related

Why is my Reverse Function Reversing All my Pairs BESIDES One?

i.e. I am given this (all possible combinations to make change for 11):
(list 1 1 1 1 1 1 1 5 5 5 5 1 1 1 10 10 10 1 1 25 25 25 25 25 25)
My code should return:
((7 . 1) (4 . 5) (3 . 1) (3 . 10) (2 . 1) (6 . 25))
so it is more readable.
However, it is returning:
((7 . 1) (4 . 5) (1 . 3) (3 . 10) (2 . 1) (6 . 25))
I don't know how to reverse the order of ALL my pairs.
This is my code:
(define (rev pair) ;; function reverses a pair, not a list.
(map (lambda (e) (cons (cdr e) (car e))) pair))
(define (rle coins)
(if (null? coins)
'()
(let loop ((firsts (list (car coins)))
(but-firsts (cdr coins)))
(if (or (null? but-firsts)
(not (equal? (car firsts) (car but-firsts))))
(rev (cons (cons (car firsts) (length firsts))
(rle but-firsts)))
(rev (loop (cons (car but-firsts) firsts) (cdr but-firsts)))))))
This is my test:
(rle (list 1 1 1 1 1 1 1 5 5 5 5 1 1 1 10 10 10 1 1 25 25 25 25 25 25))
Why not writing a classical tail-call recursive function?
Because my opinion is that named-loops are horrible constructs - unclear for the reader.
(define (rle coins (acc '()))
(if (null? coins)
(reverse acc)
(rle (cdr coins)
(if (and (not (null? acc)) (equal? (cdar acc) (car coins)))
(cons (cons (+ 1 (caar acc))
(cdar acc))
(cdr acc))
(cons (cons 1 (car coins))
acc)))))
It does correctly:
(rle (list 1 1 1 1 1 1 1 5 5 5 5 1 1 1 10 10 10 1 1 25 25 25 25 25 25))
;; '((7 . 1) (4 . 5) (3 . 1) (3 . 10) (2 . 1) (6 . 25))
First, some systematic testing (test cases should be systematic and as small as possible, not large and arbitrary):
> (rle '(2))
'((1 . 2))
> (rle '(2 3))
'((1 . 2) (3 . 1))
> (rle '(2 3 4))
'((1 . 2) (3 . 1) (1 . 4))
> (rle '(2 3 4 5))
'((1 . 2) (3 . 1) (1 . 4) (5 . 1))
> (rle '(2 3 4 5 6))
'((1 . 2) (3 . 1) (1 . 4) (5 . 1) (1 . 6))
When all the elements are unique, it looks like every other element is backwards.
> (rle '(5 5 6))
'((5 . 2) (1 . 6))
> (rle '(5 5 6 6))
'((5 . 2) (6 . 2))
> (rle '(5 5 6 6 6))
'((5 . 2) (3 . 6))
> (rle '(5 6 6 6))
'((1 . 5) (6 . 3))
When elements are repeated, the order seems a bit unpredictable.
Let's count how many times you rev each element by using triple elements with the counter as the car:
;; Flip the order of a pair.
(define (flip x)
(cons (cdr x) (car x)))
;; Add one to the car of each element and flip its cdr.
(define (rev list)
(map (lambda (x) (cons (+ 1 (car x)) (flip (cdr x)))) list))
(define (rle coins)
(if (null? coins)
'()
(let loop ((firsts (list (car coins)))
(but-firsts (cdr coins)))
(if (or (null? but-firsts)
(not (equal? (car firsts) (car but-firsts))))
(rev (cons (cons 0 (cons (car firsts) (length firsts)))
(rle but-firsts)))
(rev (loop (cons (car but-firsts) firsts) (cdr but-firsts)))))))
This creates a list that says how many times rev has been applied to each element in the result.
> (rle '(99))
'((1 1 . 99))
> (rle '(99 99))
'((2 99 . 2))
> (rle '(99 99 99))
'((3 3 . 99))
> (rle '(99 99 99 100))
'((3 3 . 99) (4 100 . 1))
> (rle '(99 99 99 100 100))
'((3 3 . 99) (5 2 . 100))
As you can see, each element has been "flipped" many times - once for every time you recurse.
This happens because you apply rev to every partial result, and not just on the final list.
The elements that have been flipped an even number of times are "backwards".
Now, your example input:
> (rle (list 1 1 1 1 1 1 1 5 5 5 5 1 1 1 10 10 10 1 1 25 25 25 25 25 25))
'((7 7 . 1) (11 4 . 5) (14 1 . 3) (17 3 . 10) (19 2 . 1) (25 6 . 25))
where we can see that the third element has been flipped an even number of times, and this is what's causing it to be backwards.
The best solution is to build your pairs in the order you want them, so you don't need to adjust them afterwards; the implementation is left as an exercise.
(The implementation is a very minor change in your procedure, and the removal of rev.)

printing pairs from a list in scheme

I'm trying to print pairs from one list kinda like a subset in scheme but with two elements just like this
(1 2 3 4 5)
((1 2) (1 3) (1 4) (1 5) (2 3) (2 4) (2 5) (3 4) (3 5) (4 5))
the code I wrote doesn't work
(define (subset x)
(if ( null? x) x
(map cons x (subset (cdr x)))))
this just return an empty list
I prefer to write the lambdas explicitly, makes it easier to understand what arguments are passed:
(define subset
(lambda (lst)
(if (null? lst)
lst
(append (map (lambda (el) (cons (car lst) el)) (cdr lst))
(subset (cdr lst)))
)))
(subset '(1 2 3 4 5))
=> ((1 . 2) (1 . 3) (1 . 4) (1 . 5) (2 . 3) (2 . 4) (2 . 5) (3 . 4) (3 . 5) (4 . 5))
EDIT: The explanation about map below is only valid in some versions of scheme, read Sylwester's comment to this answer.
map traverses n lists supplied to it and applies proc to the n elements in the same position in the lists. This means it can apply proc no more times than the length of the shortest list, but you keep giving it an empty list (from the last recursive call backwards).
(BTW this is in plain scheme)
In #lang racket that is very easy since we have combinations:
(combinations '(1 2 3 4 5) 2)
; ==> ((1 2) (1 3) (2 3) (1 4) (2 4) (3 4) (1 5) (2 5) (3 5) (4 5))
Now this does not print anything. To get it print to the terminal you can use displayln:
(displayln (combinations '(1 2 3 4 5) 2))
; ==> #<void>, ((1 2) (1 3) (2 3) (1 4) (2 4) (3 4) (1 5) (2 5) (3 5) (4 5)) printed to terminal as side effect
If order of items is also important, following can be used:
(define (subsets l)
(let loop ((n 0) ; run a loop for each item
(ol '())) ; start with blank output list
(cond
[(= n (length l)) (reverse ol)] ; output ol when last item reached;
[else
(let* ((x (list-ref l n)) ; get one item
(jl (for/list ((i l) ; get remaining list
(j (in-naturals))
#:unless (= j n))
i))
(kl (for/list ((i jl)) ; make combinations with each of remaining list
(list x i))))
(loop (add1 n) (cons kl ol)))])))
Testing:
(subsets '(1 2 3 4 5))
Output:
'(((1 2) (1 3) (1 4) (1 5))
((2 1) (2 3) (2 4) (2 5))
((3 1) (3 2) (3 4) (3 5))
((4 1) (4 2) (4 3) (4 5))
((5 1) (5 2) (5 3) (5 4)))

Can someone explain the difference between Cons and Append in scheme?

I read both of them and they seem to both construct a single list, what's their difference?
cons is the constructor for all pairs.
A proper list is () (the empty list, aka nil) or a pair where the cdr is a proper list. Any chain of pairs where the last one has () as it's cdr is a proper list (in addition to the empty list itself).
A dotted list is a pair that does not have a proper list as it's cdr. Thus a chain of pairs where the last cdr is not () matches this.
;; dotted lists
(cons 1 2) ; ==> (1 . 2)
(cons 1 (cons 2 3)) ; ==> (1 2 . 3) or (1 . (2 . 3))
;; proper lists
(cons 1 '()) ; ==> (1) or (1 . ())
(cons 1 (cons 2 '())) ; ==> (1 2) or (1 . (2 . ()))
append is a procedure that uses cons to make a list with all the elements of the argument lists left to right. A common implementation of append for just two lists would be:
(define (append lst tail)
(if (null? lst)
tail
(cons (car lst)
(append (cdr lst)
tail))))
append will fail if one of the arguments except the last is not a proper list. Tail and can be any value:
(append '(1 2 3) '(4 5)) ; ==> (1 2 3 4 5) or (1 . (2 . (3 . (4 . (5 . ())))))
(append '(1 2 3) '(4 5 . 6)) ; ==> (1 2 3 4 5 . 6) or (1 . (2 . (3 . (4 . (5 . 6)))))
(append '(1 2 3) #f) ; ==> (1 2 3 . #f) or (1 . (2 . (3 . #f)))
(append '(1 2 . 3) '(4 5 . 6)) ; ==> error `car` of number not allowed

Pairing pairs in racket

Using racket cons function I can pair two numbers into one pair for example (cons 1 2) would return a pair (1 . 2), but I can't use cons to make a pair of two pairs, (cons (cons 1 2) (cons 3 4)) returns ((1 . 2) 3 . 4), what I want is ((1 . 2) . (3 . 4))
How can I do such a thing ?
The two datums ((1 . 2) 3 . 4) and ((1 . 2) . (3 . 4)) are exactly the same. So don't worry, you've got it right.

Scheme Pair's help

How can you go from (5 . 2) to (5 2) ??
Is this what you're looking for?
(define (pair-to-list pp)
(list (car pp) (cdr pp)))
(pair-to-list '(5 . 2))
(pair-to-list (cons 5 2))

Resources