write an expression composed from car and cdr that will return c from the list '(a (b c) (d)) - scheme

write an expression composed from car and cdr that will return c from the list '(a (b c) (d)).
I am using program called Dr Racket
I tried
(car (car (car (cdr '(a (b c) (d))))))
to get c by it self but it does not work.
The error states:
mcar: contract violation
expected: mpair?
given: b

You have a small error in your code: Notice that you need the second element of the second element (which is an inner list) in the outer list. Your code is stating: retrieve the first element of the first element of the second element of the list:
(car (car (car (cdr '(a (b c) (d))))))
... Which causes an error. What you intended was this:
(car (cdr (car (cdr '(a (b c) (d))))))
Let's look at it step by step:
(cdr '(a (b c) (d))) ; => '((b c) (d)) : rest of the outer list
(car (cdr '(a (b c) (d)))) ; => '(b c) : second element of the outer list
(cdr (car (cdr '(a (b c) (d))))) ; => '(c) : rest of the inner list
(car (cdr (car (cdr '(a (b c) (d)))))) ; => 'c : second element of the inner list

(cadadr '(a (b c) (d)))
cadadr is syntactic sugar for (car (cdr (car (cdr ...)))

Related

Trying to replace all instances of an element in a list with a new element [Racket]

As the title said, I'm trying to write a function that takes a list, a variable, and an element, then replaces all instances of the variable in the list with that element.
For example:
(substitute '(C or (D or D)) 'D #f) would return
'(C or (#f or #f))
Right now what I've got is:
(define (substitute lst rep new)
(cond ((or (null? lst))
lst)
((eq? (car lst) rep)
(cons new (substitute (cdr lst) rep new)))
(else
(cons (car lst) (substitute (cdr lst) rep new)))))
Which doesn't check nested lists like my example, though it works fine when they aren't a part of the input.
And I'm having trouble with where to place recursion in order to do so - or would it be easier to flatten it all and then rebuild it after everything's been replaced in some way?
Here's another solution using pattern matching via match -
(define (sub l rep new)
(match l
((list (list a ...) b ...) ; nested list
(cons (sub a rep new)
(sub b rep new)))
((list a b ...) ; flat list
(cons (if (eq? a rep) new a)
(sub b rep new)))
(_ ; otherwise
null)))
It works like this -
(sub '(a b c a b c a b c) 'a 'z)
;; '(z b c z b c z b c)
(sub '(a b c (a b c (a b c))) 'a 'z)
;; '(z b c (z b c (z b c)))
(sub '() 'a 'z)
; '()
At first sight, your question looks similar to How to replace an item by another in a list in DrScheme when given paramters are two items and a list?. From my understanding, your question is slightly different because you also want to replace occurrences within nested lists.
In order to deal with nested lists, you must add a clause to check for the existence of a nested list, and replace all occurrences in that nested list by recursing down the nested list:
(define (subst l rep new)
(cond ((null? l)
'())
((list? (car l)) ; Check if it is a nested list.
(cons (subst (car l) rep new) ; Replace occurrences in the nested list.
(subst (cdr l) rep new))) ; Replace occurrences in the rest of the list.
((eq? (car l) rep)
(cons new
(subst (cdr l) rep new)))
(else
(cons (car l)
(subst (cdr l) rep new)))))
Example use (borrowed from the answer given by user633183):
(subst '(a b c a b c a b c) 'a 'z)
;; '(z b c z b c z b c)
(subst '(a b c (a b c (a b c))) 'a 'z)
;; '(z b c (z b c (z b c)))
(subst '() 'a 'z)
; '()
This can be done using map and recursion:
(define (subst lst rep new)
(map (lambda (x)
(if (list? x)
(subst x rep new)
(if (eq? rep x) new x))) lst))
the output:
(subst '(a b c (a b c (a b c))) 'a 'z)
; '(z b c (z b c (z b c)))

How to compute the number of times pattern in one list appears in other list in Scheme

I am stuck up in a Scheme program for about 5 hours. The program that I am working on should take two lists as input and then compute the number of times the pattern within the first list appears on the second list.
For example : > (patt '(b c) '(a b c d e b c)) ==> answer = 2
(patt '(a b c) '(a b c a b c d e a b c c c)) ==> answer = 3
(patt '((a b) c) '(a b (a b) c d e b c)) ==> answer = 1
Below is the code that I have till now.
(define (patt lis1 lis2)
(cond
((null? lis1) 0)
((null? lis2) 0)
[(and (> (length lis1) 1) (eq? (car lis1) (car lis2))) (patt (cdr lis1) (cdr lis2))]
((eq? (car lis1) (car lis2)) (+ 1 (patt lis1 (cdr lis2))))
(else (patt lis1 (cdr lis2)))
))
Can someone please help me solve this. Thanks!
Consider the subproblem of testing if a list starts with another list.
Then do this for every suffix of the list. Sum up the count of matches.
If you want non overlapping occurrences, you can have the prefix match, return the suffix of the list so that you can skip over the matching part.
Also use equals? for structural equality, not eq? which is for identity.
You need to divide the problem into parts:
(define (prefix? needle haystack)
...)
(prefix? '() '(a b c)) ; ==> #t
(prefix? '(a) '(a b c)) ; ==> #t
(prefix? '(a b c) '(a b c)) ; ==> #t
(prefix? '(a b c d) '(a b c)) ; ==> #f
(prefix? '(b) '(a b c)) ; ==> #t
(define (count-occurences needle haystack)
...)
So with this you can imagine searching for the pattern (count-occurences '(a a) '(a a a a)). When it is found from the first element you need to search again on the next. Thus so that the result is 3 for the (a a a a) since the matches overlap. Every sublist except when it's the empty list involves using prefix?
Good luck!
(define (patt list1 list2)
(let ([patt_length (length list1)])
(let loop ([loop_list list2]
[sum 0])
(if (>= (length loop_list) patt_length)
(if (equal? list1 (take loop_list patt_length))
(loop (cdr loop_list) (add1 sum))
(loop (cdr loop_list) sum))
sum))))
After giving this homework problem a little time to marinate, I don't see the harm in posting additional answers -
(define (count pat xs)
(cond ((empty? xs)
0)
((match pat xs)
(+ 1 (count pat (cdr xs))))
(else
(count pat (cdr xs)))))
(define (match pat xs)
(cond ((empty? pat)
#t)
((empty? xs)
#f)
((and (list? pat)
(list? xs))
(and (match (car pat) (car xs))
(match (cdr pat) (cdr xs))))
(else
(eq? pat xs))))
(count '(a b c) '(a b c a b c d e a b c c c)) ;; 3
(count '((a b) c) '(a b (a b) c d e b c)) ;; 1
(count '(a a) '(a a a a)) ;; 3

Scheme procedure to substitute the element in a pair

I'm trying to write a procedure: when a pair starts with a, it would return b; when a pair starts with b, it would return c; and when a pair starts with c, it would return a.
(define e '((a b) (b c) (c a)))
(define (make-encoder e)
(cond ((eq? 'a (car (assq 'a e)))
(cadr (assq 'a e)))
((eq? 'b (car (assq 'b e)))
(cadr (assq 'b e)))
((eq? 'c (car (assq 'c e)))
(cadr (assq 'c e)))))
What is returned is only 'b', so I'm wondering where my brackets are wrong in cutting off the remaining code? I have played around for so long and wondering if that's my problem, or if it something else.
I don't think it's an issue of wrong parens; I can't really see a way to tweak your code to get the desired behavior. Here's how I would do it:
(define (make-encoder assoc-list)
(lambda (lst)
(define (-> elem)
(cadr (assq elem assoc-list)))
(map -> lst)))
As you can see, when you call this procedure with an association list such as e, it will return a new function that takes a list and maps -> over it, where -> looks up the element in the association list and returns result. Hence:
> ((make-encoder e) '(a b a c a b))
'(b c b a b c)
You have looking up the value of a key in a association list with (cadr (assq k a)) but what you are missing is how to apply that to every item in a list. That is where map comes in. So:
> (map (lambda (v) (cadr (assq v '((a b) (b c) (c a))))) '(a b a c a b))
'(b c b a b c)
This can be turned into a function by placing it within lambdas or a definition and replacing the values with bound names.

Scheme removing nested duplicates

So I'm programming in scheme and made a function that removes duplicated but it doesn't work for nested. I can't really figure out a good way to do this, is there a way to modify the current code I have and simply make it work with nested? lists?
Here's my code
(define (duplicates L)
(cond ((null? L)
'())
((member (car L) (cdr L))
(duplicates (cdr L)))
(else
(cons (car L) (duplicates (cdr L))))))
So your procedure jumps over elements that exist in the rest of the list so that (duplicates '(b a b)) becomes (a b) and not (b a). It works for a flat list but in a tree you might not have a first element in that list but a list. It's much easier to keep the first occurrence and blacklist future elements. The following code uses a hash since you have tagged racket. Doing this without a hash requires multiple-value returns or mutation.
(define (remove-duplicates lst)
(define seen (make-hasheqv))
(define (ins val)
(hash-set! seen val #t)
val)
(let aux ((lst lst))
(cond ((null? lst) lst)
((not (pair? lst)) (if (hash-has-key? seen lst) '() (ins lst)))
((pair? (car lst)) (let ((a (aux (car lst))))
(if (null? a) ; if the only element is elmininated
(aux (cdr lst))
(cons a (aux (cdr lst))))))
((hash-has-key? seen (car lst)) (aux (cdr lst)))
(else (cons (ins (car lst)) ; NB! order of evaluation in Racket is left to right but not in Scheme!
(aux (cdr lst)))))))
;; test
(remove-duplicates '(a b a)) ; ==> (a b)
(remove-duplicates '(a (a) b a)) ; ==> (a b)
(remove-duplicates '(a (b a) b a)) ; ==> (a (b))
(remove-duplicates '(a b (a b) b a)) ; ==> (a b)
(remove-duplicates '(a (a . b) b a)) ; ==> (a b)
(remove-duplicates '(a b (a b . c) b a . d)) ; ==> (a b c . d)

Help explaining how `cons` in Scheme work?

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.

Resources