Scheme Programming finding items in nested loops - scheme

I have the following items
(define itemslist
(list 'a1 'b2 'c3 (list 'z1 'z2) 'd5 'e6))
My method to find items is below
(define find-item
(lambda (item itemslist)
(cond ((null? itemslist) #f)
((list? (car itemslist))
(cond ((null? itemslist) #f)
(else (find-item item (car itemslist)))))
((equal? stn (car itemslist)) (display "found"))
(else (find-stn stn (cdr itemslist)))
)
)
)
With my method above I can find a1, b2, c3, z1, z2. But when I want to find d5 onwards, it returns nothing. It seems to have skip the stack. Btw, I am just starting to learn Scheme so simple explanation would be better.
One more qns, how about if I have this
(list 'a1 'b2 'c3 (list 'z1 (list 'y1 'y2) 'z2) 'd5 'e6)
does this works as well? Thanks!

Yes, you skip lists.
Example:
'(1 '(2 3) 4)
If (list? '(2 3)) is true, the else part (outer cond) wont be evaluated so 4 is skipped.
So, either you place the else part inside list? block or you redesign your code.
If the itemlist is a list/pair you can pass it right away in a recursive call so
you can avoid writing code like (car itemslist) inside predicates thus make the code simple.
Here is a redesigned (simplified) version:
(define (find-item item l)
(cond ((equal? item l) #t)
((pair? l) (or (find-item item (car l)) (find-item item (cdr l))))
(else #f)))
Tip: you can also can write lists with '(...) notation instead of (list ...), ie
(find-item 'z2 '('a1 'b2 'c3 '('z1 '('y1 'y2) 'z2) 'd5 'e6))
#t
(find-item 'e6 '('a1 'b2 'c3 '('z1 '('y1 'y2) 'z2) 'd5 'e6))
#t

To write more for the sake of writing more... This is usually called a "tree-walk" because a nested list like that is really a binary tree. Lists are really made up of binary pairs, so when you have a pair (l . r), l is the left branch of the tree and r is the right branch of the tree.
For example, '(1 (2 3) 4) is short for '(1 . ((2 . (3 . ())) . (4 . ()))) which can be drawn as
.
/ \
1 .
/ \
/ .
/ / \
. 4 ()
/ \
2 .
/ \
3 ()
and at any pair (l . r), car gets you the left tree and cdr gets you the right. So, when you write (pair? ls), you're really asking if you're at a branch in the tree, at which point you should recur on both the left branch (car) and the right branch (cdr). Hope that helps you understand lists.

Even though you got your [specific] answer, here's something that might help you with similar questions.
(define describe
(lambda (e)
(cond #;((list? e)
`(list ,#(map describe e)))
((pair? e)
`(cons ,(describe (car e))
,(describe (cdr e))))
((vector? e)
`(vector ,#(map describe (vector->list e))))
((or (null? e) (symbol? e)) `',e)
(else e))))
This procedure prints the code that generates a given sexpr. For example:
> (describe '(a 2 b 3))
(cons 'a (cons 2 (cons 'b (cons 3 '()))))
It will also place the quotes where needed, so it places them before symbols or () but not before numbers. When you are comfortable with nested pairs, you may want to remove the #; on the third line, to generate more compact output:
> (describe '(a 2 b 3))
(list 'a 2 'b 3)
This code can teach you many things about quote. For example:
> (describe ''''a)
(list 'quote (list 'quote (list 'quote 'a)))

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?

Scheme - returning first n-elements of an array

I'm trying to write a function in Scheme that returns the first n elements in a list. I'm want to do that without loops, just with this basic structure below.
What I've tried is:
(define n-first
(lambda (lst n)
(if (or(empty? lst) (= n 0))
(list)
(append (car lst) (n-first (cdr lst) (- n 1))))))
But I'm getting an error:
append: contract violation
expected: list?
given: 'in
I've tried to debug it and it looks that the tail of the recursion crashes it, meaning, just after returning the empty list the program crashes.
When replacing "append" operator with "list" I get:
Input: (n-first '(the cat in the hat) 3)
Output:
'(the (cat (in ())))
But I want to get an appended list.
A list that looks like (1 2 3) i constructed like (1 . (2 . (3 . ()))) or if you're more familiar with cons (cons 1 (cons 2 (cons 3 '()))). Thus (list 1 2 3)) does exactly that under the hood. This is crucial information in order to be good at procedures that works on them. Notice that the first cons cannot be applied before the (cons 2 (cons 3 '())) is finished so a list is always created from end to beginning. Also a list is iterated from beginning to end.
So you want:
(define lst '(1 2 3 4 5))
(n-first lst 0) ; == '()
(n-first lst 1) ; == (cons (car lst) (n-first (- 1 1) (cdr lst)))
(n-first lst 2) ; == (cons (car lst) (n-first (- 2 1) (cdr lst)))
append works like this:
(define (append lst1 lst2)
(if (null? lst1)
lst2
(cons (car lst1)
(append (cdr lst1) lst2))))
append is O(n) time complexity so if you use that each iteration of n parts of a list then you get O(n^2). For small lists you won't notice it but even a medium sized lists of a hundred thousand elements you'll notice append uses about 50 times longer to complete than the cons one and for large lists you don't want to wait for the result since it grows exponentially.
try so
(define first-n
(lambda (l)
(lambda (n)
((lambda (s)
(s s l n (lambda (x) x)))
(lambda (s l n k)
(if (or (zero? n)
(null? l))
(k '())
(s s (cdr l) (- n 1)
(lambda (rest)
(k (cons (car l) rest))))))))))
(display ((first-n '(a b c d e f)) 4))
(display ((first-n '(a b)) 4))
In scheme you must compute mentally the types of each expression, as it does not have a type checker/ type inference included.

Mirror in scheme returns nested list w/o helper functions [duplicate]

For my programming languages class I'm supposed to write a function in Scheme to reverse a list without using the pre-made reverse function. So far what I got was
(define (reverseList lst)
(COND
((NULL? lst) '())
(ELSE (CONS (reverseList(CDR lst)) (CAR lst)))
))
The problem I'm having is that if I input a list, lets say (a b c) it gives me (((() . c) . b) . a).
How am I supposed to get a clean list without multiple sets of parenthesis and the .'s?
The problem with your implementation is that cons isn't receiving a list as its second parameter, so the answer you're building isn't a proper list, remember: a proper list is constructed by consing an element with a list, and the last list is empty.
One possible workaround for this is to use a helper function that builds the answer in an accumulator parameter, consing the elements in reverse - incidentally, this solution is tail recursive:
(define (reverse lst)
(reverse-helper lst '()))
(define (reverse-helper lst acc)
(if (null? lst)
acc
(reverse-helper (cdr lst) (cons (car lst) acc))))
(reverse '(1 2 3 4 5))
=> '(5 4 3 2 1)
You are half way there. The order of the elements in your result is correct, only the structure needs fixing.
What you want is to perform this transformation:
(((() . c) . b) . a) ; input
--------------------
(((() . c) . b) . a) () ; trans-
((() . c) . b) (a) ; for-
(() . c) (b a) ; mation
() (c b a) ; steps
--------------------
(c b a) ; result
This is easy to code. The car and cdr of the interim value are immediately available to us. At each step, the next interim-result is constructed by (cons (cdr interim-value) interim-result), and interim-result starts up as an empty list, because this is what we construct here - a list:
(define (transform-rev input)
(let step ( (interim-value input) ; initial set-up of
(interim-result '() ) ) ; the two loop variables
(if (null? interim-value)
interim-result ; return it in the end, or else
(step (car interim-value) ; go on with the next interim value
(cons ; and the next interim result
(... what goes here? ...)
interim-result )))))
interim-result serves as an accumulator. This is what's known as "accumulator technique". step represents a loop's step coded with "named-let" syntax.
So overall reverse is
(define (my-reverse lst)
(transform-rev
(reverseList lst)))
Can you tweak transform-rev so that it is able to accept the original list as an input, and thus skip the reverseList call? You only need to change the data-access parts, i.e. how you get the next interim value, and what you add into the interim result.
(define (my-reverse L)
(fold cons '() L)) ;;left fold
Step through the list and keep appending the car of the list to the recursive call.
(define (reverseList lst)
(COND
((NULL? lst) '())
(ELSE (APPEND (reverseList(CDR lst)) (LIST (CAR lst))))
))
Instead of using cons, try append
(define (reverseList lst)
(if (null? lst)
'()
(append (reverseList (cdr lst)) (list (car lst)) )
)
)
a sample run would be:
1]=> (reverseList '(a b c 1 2 + -))
>>> (- + 2 1 c b a)
car will give you just one symbol but cdr a list
Always make sure that you provide append with two lists.
If you don't give two lists to the cons it will give you dotted pair (a . b) rather than a list.
See Pairs and Lists for more information.

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.

Processing 2 lists simultaneously using append

I'm stuck on the question for Exercise 17.1.2 from HTDP. This is what I've got so far:
(define (cross alist1 alist2)
(cond
[(empty? alist1) empty]
[else (append (list (first alist1)(first alist2))
(cons (first alist1)(list (first (rest alist2))))
(cross (rest alist1) alist2))]))
(cross '(a b c) '(1 2))
;correctly outputs (list 'a 1 'a 2 'b 1 'b 2 'c 1 'c 2)
This works for the test case, but when the second list has more than 2 elements, the function falls apart.
(cross '(a b c) '(1 2 3))
;outputs (list 'a 1 'a 2 'b 1 'b 2 'c 1 'c 2)
The problem seems to be the second line after the append, because it's only cons'ing up to two elements from the second list. How should I go about resolving this? Thanks for any insight. :)
It only works for two elements in list two because you only specified it to work for two elements in list two. We need to harness the power of abstraction.
If we were working in imperative languages, then we'd use nested for-loops on this problem. You start on the first element of alist1 and match with all the elements of alist2. Then you move on to the second element of alist1 and match with all the elements of alist2. Since we're working in a functional language (Scheme) we'll use nested functions instead of nested for-loops.
You want to write a function that takes 'a and '(1 2 3) and produces '(a 1 a 2 a 3) and then another function to call the first one with varying values of 'a. Relevant code that you should ignore if you don't want the solution spoiled for you below.
(define (cross alist1 alist2)
(cond
((null? alist1) '())
(else
(append (innercross (car alist1) alist2)
(cross (cdr alist1) alist2)))))
(define (innercross a1 alist2)
(cond
((null? alist2) '())
(else
(cons a1 (cons (car alist2) (innercross a1 (cdr alist2)))))))

Resources