I am implementing a procedure 'map2' that takes in two lists and returns the sum of each element. If the lists are uneven, only the sums of the shortest list is returned. My code is:
(define (map2 proc items1 items2)
(if (null? items1)
'()
(cons (proc (car items1) (car items2))
(map2 proc (cdr items1) (cdr items2)))))
Example of use should be:
(maps2 + '(1 2 3 4) '(3 4 5)) --> (4 6 8)
My question is how do implement the part that handles uneven lists?
Your solution is almost correct - you just have to check both lists and stop, when one of them is empty.
(define (map2 proc items1 items2)
(if (or (null? items1) (null? items2))
'()
(cons (proc (car items1) (car items2))
(map2 proc (cdr items1) (cdr items2)))))
Example:
> (map2 + '(1 2 3 4) '(3 4 5))
'(4 6 8)
> (map2 * '(1 2) '(3 4 5))
'(3 8)
Related
I started learning Scheme today, and wanted to write a function that would reverse a list (only surface level, nested lists stay in the same order).
Heres the function I made:
(define reverse (lambda (lst)
(if (> (length lst) 0)
(cons (reverse(cdr lst)) (car lst))
'()
)))
I thought it would just continuously add the values before everything after it so in the end it's reversed, but when doing (reverse '(5 12 31 7 98 13)), I should get (13 98 7 31 12 5), but instead I get '((((((() . 13) . 98) . 7) . 31) . 12) . 5). How come it's adding periods and parenthesis instead of adding the number to the list?
(list x y ..... z) list structure is constructed like this in Scheme:
(cons x
(cons y
…
…
(cons z '())))
if you use append instead of cons and put your (car lst) into a list of its own, your code will work:
(define reverse
(lambda (lst)
(if (> (length lst) 0)
;;(cons (reverse (cdr lst)) (car lst) )
(append (reverse (cdr lst)) (list (car lst)))
'()
)))
The list (13 98 7 31 12 5) is a visualization of the pairs (13 . (98 . (7 . (31 . (12 . (5 . ())))))). If the cdr is a pair or the empty list the dot and one set of parens is omitted. The code to create this structure is (cons 13 (cons 98 (cons 7 (cons 31 (cons 12 (cons 5 '())))))) while the structure your function creates is (cons (cons (cons (cons (cons (cons 13 '()) 98) 7) 31) 12) 5).
When iterating a list you always do it in order. eg. (1 2 3) is quite difficult to do in reverse. However when creating lists you always do them from end to beginning. eg. (cons 1 (cons 2 (cons 3 '()))) will have to evaluate the cons with 3 before the one with 2 etc. This can be used for a very efficent reverse using an accumulator:
(define (reverse lst acc)
(if (null? lst)
acc
(reverse (cdr lst)
(cons (car lst) acc))))
So imagine calling this (reverse '(1 2 3) '()):
(reverse '(1 2 3) '()) ; =>
(reverse '(2 3) (cons 1 '())) ; ==>
(reverse '(3) (cons 2 '(1))) ; ==>
(reverse '() (cons 3 '(2 1))) ; ==>
'(3 2 1)
How can I add a parentheses in a list? For example,
(multiply '(1 2) '(1 2 3))
It should output ((1 2 3) (2 4 6))
This is what I have now
(define multiply
(lambda (los1 los2)
(cond
((null? los1) '())
((null? los2) '())
(else (cons (* (car los1) (car los2))
(append (multiply(list (car los1)) (cdr los2))
(multiply(cdr los1) los2)))))))
The output I get is (1 2 3 2 4 6).
P/S: If this is a bad question or anything, don't hesitate to tell me or scold me. I am trying to learn to use stackoverflow.
Think about what the implications of the input and the output are. I imagine that you cannot do this with one single recursive procedure, but you can do it with two.
(list-multiply 5 '(1 2 3))
; ==> (5 10 15)
When you have that you iterate over the first list and use list-multiply for each element and of course the second argument is never iterated, it's just passed along.
(multiply '(1 2) '(1 2 3))
; ==> (cons (list-multiply 1 '(1 2 3))
; (cons (list-multiply 2 '(1 2 3))
; '()))
; ==> ((1 2 3) (2 4 6))
You can implement this simply by useinfg higher order functions:
(define (multiply lst1 lst2)
(map (lambda (e1)
(map (lambda (e2) (* e1 e2)) lst2))
lst1))
Notice the double map. One that iterates lst1 to make elements in the result and a second map that multiplies the one element with each element of the list. You might imagine that since these look similar the two recursive functions probably have a lot in common too.
PS: Learn to solve your problems without list and append. (list 1 2 3) is just a procedure that is equivalent to (cons 1 (cons 2 (cons 3 '()))) and (append '(1 2 3) '(4 5 6)) is equivalent to (cons 1 (cons 2 (cons 3 '(4 5 6)))). Try always building lists from end to beginning and in the event you need the opposite it might just need a reverse in the end.
I am quite new with Scheme and with StackOverflow as well!
So, for the first contact I would like to do something simple and easy in Scheme.
I want to define a function that substracts the elements of the introduced list.
For example, the inputs should be: (sub '(4 12 6) '(0 6 3))
And the output should be: (4 6 3)
Thanks!!
What you'll need is to have a base case where you check if either list is empty and evaluate it to the empty list or you make a pair with the calculation of the first element of each list and the recursion for the rest of both lists. Basically you end up with:
(cons (- 4 0) (cons (- 12 6) (cons (- 6 3) '()))) ; ==> (4 6 3)
As an example of a recursive list processing function here is one that negates all elements:
(define (negate-list lst)
(if (null? lst)
'()
(cons (- (car lst))
(negate-list (cdr lst)))))
(negate-list '(1 2 3 4)) ; ==> (-1 -2 -3 -4)
Now there are even more fancy ways to do this. Eg,. you can use tail recursion:
(define (negate-list lst)
(let loop ((lst lst) (acc '()))
(if (null? lst)
(reverse acc)
(loop (cdr lst)
(cons (- (car lst)) acc)))))
You can use map:
(define (negate-list lst)
(map - lst))
So there you go. you're half way there.
I am trying to list sucessive averages of elements in a list in reverse, for example in a list of (1 2 3) i try to get (3+2+1/3 2+1/2 1) here is an example of a list i tried my code on.
(list 2 3 4 5 6)
For some reason the values returned are " (4 7/2 4 7/2 4)". This is the code
(define (sucessive-avg lst)
(if (=(length lst) 1)
lst
(cons(avg(reverse lst)) (sucessive-avg(cdr(reverse lst))))))
The problem does not come from my avg so i dont know what is wrong with it
How many times will you call reverse? Try to do a step-by-step execution of your code to understand what is going on.
You could write a function which collect averages for the successives CDRs of a list, and call it with a reversed list:
(define (successive-averages lst)
(if (null? lst)
lst
(cons (avg lst)
(successive-averages (rest lst))))
(successive-averages (reverse (list 2 3 4 5 6)))
#coredump's answer is a pretty good start but it doesn't use proper tail recursion and it looks like it's averaging the wrong parts of the list
for example in a list of (1 2 3) i try to get (3+2+1/3 2+1/2 1)
For a list of '(2 3 4 5 6) my answer will give you
'((avg '(2 3 4 5 6))
(avg '(2 3 4 5))
(avg '(2 3 4))
(avg '(2 3))
(avg '(2)))
This seems to match your description more accurately.
Here's the code
(define (avg lst)
(/ (foldl + 0 lst)
(length lst)))
(define (successive-avg lst)
(define (iter res lst)
(if (empty? lst)
(reverse res)
(iter (cons (avg lst) res) (rest lst))))
(iter '() (reverse lst)))
(print (successive-avg '(2 3 4 5 6)))
Output
'(4 3 1/2 3 2 1/2 2)
You don't actually need to recall reverse or average at all. The reason you don't need average is that you can keep a running sum (in my code via a lambda chain) and an explicit count. And sense you want the result of the deepest recursion first, consing running average onto an acumulator as you recure gives you the right final order.
(define (successiveAvg Lst)
(cond ((null? Lst)
(error "succesiveAvg requires a non-empty list"))
((fold (lambda (acc x)
(if acc (number? x) #f))
#t
Lst)
(error "succesiveAvg requires a list of numbers" Lst))
(else
(let ((inc (lambda (x)
(+ 1 x)))
(f (lambda (x)
(lambda (y) (+ x y)))))
(let loop ((acc '())
(c (lambda (x) x))
(L lst)
(i 1))
(if (null? L)
acc
(loop (cons (/ (c (car L)) i)
acc)
(f (c (car L)))
(cdr L)
(inc i))))))))
(successiveavg '(2 3 4 5 6))
;Value 3: (4 7/2 3 5/2 2)
I'm using R5RS standart of Scheme implementation.
Now imagine you have to find out if an element '(2 3 4) is in a list '(1 2 3 4).
As for the example, and more strictly, you wish:
1. (is-in? '(2 3 4) '(1 2 3 4)) -> #f
2. (is-in? '(2 3 4) '(1 (2 3 4)) -> #t
Question: how to get that kind of behaviour, as in example 1?
Let me explain: when you search throught a list, you could use either car or cdr to get its parts. Now if you recursively go throught the list, you eventually get:
3. (cdr '(1 2 3 4)) -> '(2 3 4)
4. (cdr '(1 (2 3 4)) -> '((2 3 4))
So eventually, we got 2 lists. And you can see here, that sublist '(2 3 4) is contained by both results from 3 and 4.
Please see the contradiction of 3 and 4 with 1 and 2: while '(2 3 4) is not contained in '(1 2 3 4), recursive call of cdr returns '(2 3 4), which is equal to '(2 3 4) - and using equal? function, somewhere inside recursive calls, we eventually get #t for both 1 and 2:
5. (is-in? '(2 3 4) '(1 2 3 4)) -> #t
6. (is-in? '(2 3 4) '(1 (2 3 4)) -> #t
So how to get that kind of behaviour from 1? I want to have a function, which works with all different types of data. Here's my function, which works like 5 and 6 (throught should work as 1 and 2):
(define or (lambda (x y)
(cond ((eq? x y) (eq? x #t))
(#t #t)
)
)
)
(define and (lambda (x y)
(cond ((eq? x y) (eq? x #t))
(#t #f)
)
)
)
(define atom? (lambda (x)
(not (pair? x))
)
)
(define length (lambda (x)
(cond ((eq? x '()) 0)
((atom? x) 1)
(#t (+ (length (car x)) (length (cdr x))))
)
)
)
(define equal? (lambda (x y)
(cond ((and (atom? x) (atom? y)) (eq? x y))
((not (eq? (length x) (length y))) #f)
((not (and (pair? x) (pair? y))) #f)
(#t (and (equal? (car x) (car y)) (equal? (cdr x) (cdr y))))
)
)
)
(define is-in? (lambda (x y)
(cond ((equal? x y) #t)
(#t (cond ((pair? y) (or (is-in? x (car y)) (cond ((eq? (length y) 1) #f)
(#t (is-in? x (cdr y)))
)))
(#t #f)
)
)
)
)
)
Update:
What I want is to have a general function, which can tell you if some object is inside another object. I name entities object to emphasize that the function should work with any input values, simple or complicated like hell.
Example usages:
1. (is-in? 1 '(1 2 3)) ;-> #t
2. (is-in? '(1) '(1 2 3)) ;-> #f
3. (is-in? '(2 . 3) '(1 2 . 3)) ;-> #f
4. (is-in? '(2 . 3) '(1 (2 . 3))) ;-> #t
5. (is-in? '2 '(1 2 . 3)) ;-> #t
6. (is-in? '(2) '(1 2 . 3)) ;-> #f
7. (is-in? '(1 2 (3 4 (5 6 . (7 . 8)) 9) 10 11 (12 . 13)) '(1 (2 3 ((4 ((6 (3 . ((1 2 (3 4 (5 6 . (7 . 8)) 9) 10 11 (12 . 13)))) 3) 4)) 5) 2))) ;-> #t
8. (is-in? '(2 3 4) '((1 (2 3 4)) (1 2 3 4))) ;-> #t
9. (is-in? '(2 3 4) '(1 2 3 4)) ;-> #f
10. (is-in? '(2 3 4) '(1 (2 3 4))) ;-> #t
11. (is-in? '(1) '(1)) ;-> #t
First of all - why are you redefining and, or, equal? and length? those are built-in primitives. Also your definition of atom? is wrong, it should be:
(define (atom? x)
(and (not (pair? x))
(not (null? x))))
I guess you need to implement this from scratch as part of a homework. Let's see how that can be accomplished, fill-in the blanks to get your answer:
(define (is-in? ele lst)
(or <???> ; trivial case: ele == list
(member? ele lst))) ; call helper procedure
(define (member? ele lst)
(cond ((null? lst) ; if the list is empty
<???>) ; then the element is not in the list
((atom? lst) ; if the list is not well-formed
(equal? <???> <???>)) ; then test if ele == list
(else ; otherwise
(or (equal? ele <???>) ; test if ele == the 1st element in the list
(member? ele <???>) ; advance the recursion over the `car`
(member? ele <???>))))) ; advance the recursion over the `cdr`
Notice that the second case in member? is needed because in the examples given there are malformed lists (ending in a non-null value). The above solution will correctly handle all of the examples provided in the question.
(define (is-in? e lst)
(cond ((null? lst) #f) ; if list is empty, we failed
((eq? e (car lst)) #t) ; check 1st element of list
((list? (car lst)) (is-in? e (append (car lst) (cdr lst)))) ; search inside car if it is a list
(#t (is-in? e (cdr lst))))) ; check rest of list
You can replace eq? with something more elaborate to handle other definitions of equality.
Note: this assumes that all sequences are lists; you'll have to tweak it to handle dotted-pairs that are not lists.