Memv procedure in Scheme - scheme

(define memv2
(lambda (x l)
(cond
((null? l) #f)
((eqv? (car l) x)
cdr l)
(else
(memv2 x (cdr l))))
Studying for an exam - this code has been provided in my notes as a replication of the built in memv function in Scheme. I was wondering if someone could explain what the #f is doing in this situation. Is it exiting the loop?
(memv takes in an element and a list, and returns the list from the point of the element onward, for example: (memv 2 '(1 2 3 4 5)) would return (2 3 4 5))

The #f value is returned when the procedure finishes traversing the list, which means that the searched element was not found, thus ending the recursion.

Related

Improving an iterative function in scheme

I often struggle writing iterative functions in scheme: it makes writing recursive procedures much simpler. Here is an example of trying to square items in a list using an iterative procedure:
(define square (lambda (x) (* x x)))
(define (square-list items)
(define result nil) ; set result
(define (iter items-remaining)
(if (null? items-remaining)
result
(set! result (cons (car items-remaining) (iter (cdr items-remaining))))))
(iter items))
(square-list '(1 2 3 4 5))
; (4 9 16 25)
My main question about this is:
Is there a way to do this procedure without having to first define the result before the inner procedure? I was trying to make the iterative procedure have the function prototype of define (iter items-remaining answer) but was having a hard time implementing it that way.
And if not, why isn't that possible?
The posted code does not work; but even when fixed up so that it does work, this would not be an idiomatic Scheme solution.
To make the posted code work:
nil must be replaced with '(), since Scheme does not represent the empty list with nil
square must be called on the car of items-remaining
set! should modify result by adding squared numbers to it, not by trying to add the result of a recursive call. This won't work at all here because set! returns unspecified values; but even if it did work, this would not be tail-recursive (i.e., this would not be an iterative process)
The value of result must be returned, and it will have to be reversed first since result is really an accumulator
Here is a fixed-up version:
(define (square-list-0 items)
(define result '()) ; set result
(define (iter items-remaining)
(cond ((null? items-remaining)
result)
(else
(set! result (cons (square (car items-remaining))
result))
(iter (cdr items-remaining)))))
(iter items)
(reverse result))
A better solution would not use mutation, and would not need (define result '()):
(define (square-list-1 xs)
(define (iter xs acc)
(if (null? xs)
(reverse acc)
(iter (cdr xs) (cons (square (car xs)) acc))))
(iter xs '()))
Here an accumulator, acc, is added to the lambda list for the iter procedure. As results are calculated, they are consed onto acc, which means that at the end of this process the first number in acc is based on the last number in xs. So, the accumulator is reversed before it is returned.
Another way to do this, and probably a more idiomatic solution, is to use a named let:
(define (square-list-2 xs)
(let iter ((xs xs)
(acc '()))
(if (null? xs)
(reverse acc)
(iter (cdr xs) (cons (square (car xs)) acc)))))
This is a bit more concise, and it lets you bind arguments to their parameters right at the beginning of the definition of the iter procedure.
All three of the above solutions define iterative processes, and all three give the same results:
> (square-list-0 '(1 2 3 4 5))
(1 4 9 16 25)
> (square-list-1 '(1 2 3 4 5))
(1 4 9 16 25)
> (square-list-2 '(1 2 3 4 5))
(1 4 9 16 25)
Of course, you could just use map:
> (map square '(1 2 3 4 5))
(1 4 9 16 25)

Nested List Issue in Lisp

So I have to write a method that takes in a list like (nested '(4 5 2 8)) and returns (4 (5 () 2) 8).
I figured I needed to write 3 supporting methods to accomplish this. The first gets the size of the list:
(define (sizeList L)
(if (null? L) 0
(+ 1 (sizeList (cdr L)))))
input : (sizeList '(1 2 3 4 5 6 7))
output: 7
The second drops elements from the list:
(define (drop n L)
(if (= (- n 1) 0) L
(drop (- n 1) (cdr L))))
input : (drop 5 '(1 2 3 4 5 6 7))
output: (5 6 7)
The third removes the last element of a list:
(define (remLast E)
(if (null? (cdr E)) '()
(cons (car E) (remLast (cdr E)))))
input : (remLast '(1 2 3 4 5 6 7))
output: (1 2 3 4 5 6)
For the nested method I think I need to do the car of the first element, then recurse with the drop, and then remove the last element but for the life of me I can't figure out how to do it or maybe Im just continually messing up the parenthesis? Any ideas?
Various recursive solutions are possible, but the problem is that the more intuitive ones have a very bad performance, since they have a cost that depends on the square of the size of the input list.
Consider for instance this simple solution:
; return a copy of list l without the last element
(define (butlast l)
(cond ((null? l) '())
((null? (cdr l)) '())
(else (cons (car l) (butlast (cdr l))))))
; return the last element of list l
(define (last l)
(cond ((null? l) '())
((null? (cdr l)) (car l))
(else (last (cdr l)))))
; nest a linear list
(define (nested l)
(cond ((null? l) '())
((null? (cdr l)) l)
(else (list (car l) (nested (butlast (cdr l))) (last l)))))
At each recursive call of nested, there is a call to butlast and a call to last: this means that for each element in the first half of the list we must scan twice the list, and this requires a number of operations of order O(n2).
Is it possible to find a recursive solution with a number of operations that grows only linearly with the size of the list? The answer is yes, and the key to this solution is to reverse the list, and work in parallel on both the list and its reverse, through an auxiliary function that gets one element from both the lists and recurs on their cdr, and using at the same time a counter to stop the processing when the first halves of both lists have been considered. Here is a possible implementation of this algorithm:
(define (nested l)
(define (aux l lr n)
(cond ((= n 0) '())
((= n 1) (list (car l)))
(else (list (car l) (aux (cdr l) (cdr lr) (- n 2)) (car lr)))))
(aux l (reverse l) (length l)))
Note that the parameter n starts from (length l) and is decreased by 2 at each recursion: this allows to manage both the cases of a list with an even or odd number of elements. reverse is the primitive function that reverses a list, but if you cannot use this primitive function you can implement it with a recursive algorithm in the following way:
(define (reverse l)
(define (aux first-list second-list)
(if (null? first-list)
second-list
(aux (cdr first-list) (cons (car first-list) second-list))))
(aux l '()))

multiplying list of items by a certain number 'x'

How would you write a procedure that multiplies each element of the list with a given number (x).If I give a list '(1 2 3) and x=3, the procedure should return (3 6 9)
My try:
(define (mul-list list x)
(if (null? list)
1
(list(* x (car list))(mul-list (cdr list)))))
The above code doesnt seem to work.What changes do I have to make ? Please help
Thanks in advance.
This is the text book example where you should use map, instead of reinventing the wheel:
(define (mul-list lst x)
(map (lambda (n) (* x n)) lst))
But I guess that you want to implement it from scratch. Your code has the following problems:
You should not call list a parameter, that clashes with the built-in procedure of the same name - one that you're currently trying to use!
The base case should return an empty list, given that we're building a list as output
We build lists by consing elements, not by calling list
You forgot to pass the second parameter to the recursive call of mul-list
This should fix all the bugs:
(define (mul-list lst x)
(if (null? lst)
'()
(cons (* x (car lst))
(mul-list (cdr lst) x))))
Either way, it works as expected:
(mul-list '(1 2 3) 3)
=> '(3 6 9)
For and its extensions (for*, for/list, for/first, for/last, for/sum, for/product, for/and, for/or etc: https://docs.racket-lang.org/reference/for.html) are very useful for loops in Racket:
(define (ml2 lst x)
(for/list ((item lst))
(* item x)))
Testing:
(ml2 '(1 2 3) 3)
Output:
'(3 6 9)
I find that in many cases, 'for' implementation provides short, simple and easily understandable code.

Return the first and last element in the list Scheme

Pretty straightforward question. My initial approach was to define another procedure to find the last element of lst within first-last. After finding the last element I appended it with the first element of lst (car lst).
This is how append works.
(append list1 list2)
e.g., (append '(1 2 3) '(2 1 5)) -> (1 2 3 2 1 5)
I'm wondering if the problem is just with my syntax but I am not sure.
(define (first-last lst)
(define (last lst)
(cond ((null? (cdr lst))(car lst))
(else (last (cdr lst)))))
(append(car lst)(last lst)))
The error occurs in the
(append(car lst)(last lst)))
"mcar: contract violation
expected: mpair?
given: 1"
This is my first question on stack, so I'm sorry if the question is not presented in the correct way.
append is only for joining two or more lists. Here, though, you're not joining existing lists, but building a list from two elements. For that, use list:
(list (car lst) (last lst))
If you can use match, a neat solution is possible:
(define first-last
(lambda (x)
(match x
((first rest ... last)
(list first last))
((only) (list only only))
(_ #f))))
Of course, you could return something other than #f in the catch-all clause.

Finding the overall average of nested lists in Scheme?

Hey guys, I'm using MIT Scheme and trying to write a procedure to find the average of all the numbers in a bunch of nested lists, for example:
(average-lists (list 1 2 (list 3 (list 4 5)) 6)))
Should return 3.5. I've played with the following code for days, and right now I've got it returning the sum, but not the average. Also, it is important that the values of the inner-most lists are calculated first, so no extracting all values and simply averaging them.
Here's what I have so far:
(define (average-lists data)
(if (null? data)
0.0
(if (list? (car data))
(+ (average-lists (car data)) (average-lists (cdr data)))
(+ (car data) (average-lists (cdr data))))))
I've tried this approach, as well as trying to use map to map a lambda function to it recursively, and a few others, but I just can't find one. I think I'm making thing harder than it should be.
I wrote the following in an effort to pursue some other paths as well, which you may find useful:
(define (list-num? x) ;Checks to see if list only contains numbers
(= (length (filter number? x)) (length x)))
(define (list-avg x) ;Returns the average of a list of numbers
(/ (accumulate + 0 x) (length x)))
Your help is really appreciated! This problem has been a nightmare for me. :)
Unless the parameters require otherwise, you'll want to define a helper procedure that can calculate both the sum and the count of how many items are in each list. Once you can average a single list, it's easy to adapt it to nested lists by checking to see if the car is a list.
This method will get you the average in one pass over the list, rather than the two or more passes that solutions that flatten the list or do the count and the sums in two separate passes. You would have to get the sum and counts separately from the sublists to get the overall average, though (re. zinglon's comment below).
Edit:
One way to get both the sum and the count back is to pass it back in a pair:
(define sum-and-count ; returns (sum . count)
(lambda (ls)
(if (null? ls)
(cons 0 0)
(let ((r (sum-and-count (cdr ls))))
(cons (+ (car ls) (car r))
(add1 (cdr r)))))))
That procedure gets the sum and number of elements of a list. Do what you did to your own average-lists to it to get it to examine deeply-nested lists. Then you can get the average by doing (/ (car result) (cdr result)).
Or, you can write separate deep-sum and deep-count procedures, and then do (/ (deep-sum ls) (deep-count ls)), but that requires two passes over the list.
(define (flatten mylist)
(cond ((null? mylist) '())
((list? (car mylist)) (append (flatten (car mylist)) (flatten (cdr mylist))))
(else (cons (car mylist) (flatten (cdr mylist))))))
(define (myavg mylist)
(let ((flatlist (flatten mylist)))
(/ (apply + flatlist) (length flatlist))))
The first function flattens the list. That is, it converts '(1 2 (3 (4 5)) 6) to '(1 2 3 4 5 6)
Then its just a matter of applying + to the flat list and doing the average.
Reference for the first function:
http://www.dreamincode.net/code/snippet3229.htm

Resources