Scheme - Using cons properly to create lists - scheme

I've been trying to solve exercise 2.20 of SICP, where "dotted-tail" notation is introduced. My problem is that, instead of returning a proper list with results, my function returns a nested list.
I know that there is something wrong with the way I'm calling cons, but I still have no clue of how to solve the issue.
So here is my function:
(define (same-parity first . items)
(define (speccar items)
(cond ((null? items) 2)
((not (pair? items)) (modulo items 2))
(else (modulo (car items) 2))))
(define (iter-parity first items result)
(let ((parityFirst (modulo first 2)) (samepar (speccar items)))
(if (null? items)
result
(if (= parityFirst samepar)
;; This next line is where the problem is...
(iter-parity first (cdr items) (cons (list result) (list (car items))))
(iter-parity first (cdr items) result)))))
(iter-parity first items first))
Test:
(same-parity 1 2 3 4 5)
((((1) 3)) 5)
Now, I've read the following answers that deal with a similar problem:
Cons element to list vs cons list to element in Scheme
How to use 'cons' without generating nested lists in Scheme?
They certainly make it clear where the problem is coming from, but how does one go about to actually implement a proper solution?
And, if possible, what is the correct way of "thinking" in Scheme to avoid these traps/pitfalls?

You're incorrectly building the output list - remember: the first argument to cons should be the current element and the second argument, the result list.
Also, given that you're using tail recursion, you'll have to reverse the output at the end to preserve the same order as in the original list. Try this:
(define (same-parity first . items)
(define (speccar items)
(cond ((null? items) 2)
((not (pair? items)) (modulo items 2))
(else (modulo (car items) 2))))
(define (iter-parity first items result)
(let ((parityFirst (modulo first 2))
(samepar (speccar items)))
(if (null? items)
(reverse result)
(if (= parityFirst samepar)
(iter-parity first
(cdr items)
(cons (car items) result))
(iter-parity first
(cdr items)
result)))))
(iter-parity first items (list first)))
The above solution can be greatly simplified if we use built-in procedures (don't reinvent the wheel!). This is the recommended way to write programs in Scheme - adhering to a functional style:
(define (same-parity head . tail)
(if (even? head)
(filter even? (cons head tail))
(filter odd? (cons head tail))))
Either way, it works as expected:
(same-parity 1 2 3 4 5)
=> '(1 3 5)

Related

Can't get the end list i want in swapping procedure

Ultimately, i shall be trying to reimplement sorting algorithms in scheme for linked lists. I have written a subprocedure that will help me along the way. The goal is to simply swap 2 elements, given as arguments "pair1 and pair2" and then return the list.
(define (cons-til lst until)
(cond
((or (null? lst) (eq? (car lst) until)) '())
(else (cons (car lst) (cons-til (cdr lst) until)))))
(define (swap lst pair1 pair2)
(cons (cons (append (cons-til lst (car pair1))
(car pair2)) (car pair1)) (cdr pair2)))
(define my-list '(1 2 3 4 5 6 7))
(swap my-list (cdr (cdr my-list)) (cdr (cdr (cdr my-list))))
When the code is executed, it returns:
(((1 2 . 4) . 3) 5 6 7)
How can i fix this in order to have a plain scheme list. The element seems to have swapped correctly.
Two suggestions:
Do you really want to write n cdr calls to index the nth element? I recommend strongly using integer indexes (if you need them, that is).
Referring to elements by index in a linked list (i. e. “random access”) is not very efficient most of the time, especially when done in loops. I strongly recommend using either vectors or a better suited algorithm that doesn't need random access, e. g. merge sort.
(define (swap2 lst pair1 pair2)
(append (append (append (cons-til lst (car pair1))
(list (car pair2)))
(list (car pair1))) (cdr pair2)))
This code seems to work. I'm not sure this is completely efficient or a smart solution to the problem. Looking forward to other suggestions. The value given back is '(1 2 4 3 5 6 7)

Implementing powerset in scheme

I am trying to implement a powerset function in Scheme in two ways.
One way is using tail recursion, and I did it like this:
(define (powerset list)
(if (null? list) '(()) ;; if list is empty, its powerset is a list containing the empty list
(let ((rest (powerset (cdr list)))) ;; define "rest" as the result of the recursion over the rest of list
(append (map (lambda (x) (cons (car list) x)) rest) ;; add the first element of list to the every element of rest (which is a sublist of rest)
rest)))) ;; and append it to rest itself (as we can either use the current element (car list), or not
Which works fine.
Another way is using foldr, and this is where I face some issues.
My current implementation is as follows:
(define (powerset-fr list)
(foldr (lambda (element result) ;; This procedure gets an element (and a result);
(if (null? result) ;; if starting with the empty list, there is nothing to "fold over".
(cons '() (cons element result))
(foldr (lambda (inner-element inner-result)
(append (cons element result) inner-result))
'(())
result)))
'() ;; The result is initialized to the empty list,
list)) ;; and the procedure is being applied for every element in the first list (list1)
Which yields a poor result.
I'll try to explain shortly how did I approach this problem so far:
foldr runs over every element in the given set. For each such element, I should add some new elements to the powerset.
Which elements should these be? One new element for each existing element in the powerset, where is append the current element in list to the existing element in powerset.
This is why I thought I should use foldr twice in a nested way - one to go over all items in given list, and for each item I use foldr to go over all items in "result" (current powerset).
I faced the problem of the empty list (nothing is being added to the powerset), and thus added the "if" section (and not just foldr), but it doesn't work very well either.
I think that's it. I feel close but it is still very challenging, so every help will be welcomed.
Thanks!
The solution is simpler, there's no need to use a double foldr, try this:
(define (powerset-fr lst)
(foldr (lambda (e acc)
(append (map (lambda (x) (cons e x))
acc)
acc))
'(())
lst))
If your interpreter defines append-map or something equivalent, then the solution is a bit shorter - the results will be in a different order, but it doesn't matter:
(define (powerset-fr lst)
(foldr (lambda (e acc)
(append-map (lambda (x) (list x (cons e x)))
acc))
'(())
lst))
Either way, it works as expected:
(powerset-fr '(1 2 3))
=> '((1 2 3) (1 2) (1 3) (1) (2 3) (2) (3) ())

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.

removing last element of a list(scheme)

So I have to remove the last element of a list in scheme.
For example, let's say I have a list (1 2 3 4). I need to return:
(1 2 3)
My idea:
reverse(list)
car(list)
reverse(list)
Is there a reverse function in scheme(racket)?
You wrote: "reverse, car, reverse". I believe you meant to write "reverse, cdr, reverse". There's nothing wrong with this solution; it's linear in the size of the list, just like any solution to this that uses the standard lists.
As code:
;; all-but-last: return the list, not including the last element
;; list? -> list?
(define (all-but-last l) (reverse (cdr (reverse l))))
If the multiple traversal of the list or the needless construction of another list copy bothers you, you can certainly avoid it, by writing the thing directly.
Given your almost-solution, I'm going to assume that this isn't homework.
Here's what it would look like, in racket:
#lang racket
(require rackunit)
;; all-but-last : return the list, except for the last element
;; non-empty-list? -> list?
(define (all-but-last l)
(cond [(empty? l) (error 'all-but-last "empty list")]
[(empty? (rest l)) empty]
[else (cons (first l) (all-but-last (rest l)))]))
(check-equal? (all-but-last '(3 4 5))
'(3 4))
There is a reverse, but using it would not be very efficient. I suggest the following recursive function.
(define (remove-last lst)
(if (null? (cdr lst))
'()
(cons (car lst) (remove-last (cdr lst)))))
(remove-last '(1 2 3 4)) ; returns '(1 2 3)
The if checks whether it is at the last element of the list.
SRFI 1 (activate in Racket using (require srfi/1)) has a drop-right function:
(drop-right '(1 2 3 4) 1) ; => (1 2 3)
I would do a recursive function that goes down the list and attaches the element (using cons) if the element after it is not the last, and appends nothing if it isn't.
I haven't done scheme for years though so that's as far as I can go.
Someone can run with how to implement it (unless it's homework then they probably shouldn't!)
I've done something simpler than: reverse(list), car(list), reverse(list) to get the last element, check out:
(define (last-one liste)
(if(null? (cdr liste))
null
(cons (car liste) (last-one (cdr liste)))
)
)
Those who are looking for another way can check this out:
(define (removing-last xx)
(remove (list-ref xx (- (length xx) 1)) xx))
I would write a simple recursion, altering the typical "empty? mylist" base case to "empty? (rest mylist)," so that I can return empty when the input list is only 1 element.
(define (removelast mylist)
(cond
[(empty? (rest mylist)) empty]
[(cons? mylist) (cons (first mylist) (removelast (rest mylist)))]))
(removelast (list 1 2 3 4 5))
By the way, this code is in Racket/PLT Scheme, a subset of Scheme.

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