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) ())
Related
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.
I have the following procedure for creating all prime-pairs in a list:
(define (prime-pairs lst)
(define (split lst pos)
(list (drop-right lst pos) (take-right lst pos)))
(define (prime-pairs-iter n acc)
(cond ((= n 0) (filter (lambda (e) (not (null? e))) acc))
(else (prime-pairs-iter (- n 1)
(let ((s (split lst n)))
(if (and (prime? (list->number (car s)))
(prime? (list->number (cadr s))))
(append s acc)
acc))))))
(prime-pairs-iter (- (length lst) 1) '()))
(Full code: https://gist.github.com/anonymous/b8cfcb0bf021be9ef9c8)
What I want prime-pairs to do is create a list of every pair in the lst that consists of two primes. The numbers are represented in a list format as follows: 11 would be '(1 1).
Unfortunately, when I run this code the (filter (lambda (e) (not (null? e))) acc)) does not seem to remove the '() from the end result, and I end up with a long list of empty values and the wanted pairs.
If I use a (filter null? acc)) a list of empty values does remain. So the other way around (filtering out the actual values) does work.
How can I filter out the nulls of the returned list?
Currently, your prime-pairs function always returns one value: either an empty list, or the prime pairs. Using map, there is no way to avoid the empty lists, without doing further filtering on the result of the map.
One alternative is to return a list of results, and use append-map instead of map. Change your prime-pairs to return either an empty list, or a singleton list containing your prime pairs; this simulates returning zero or one value, rather than always one value. Like so:
(cond ((zero? n) (if (null? acc)
'()
(list acc)))
...)
Now, use append-map:
(append-map prime-pairs primes-list-split)
and you should have the results you seek. (See my forked gist for full code.)
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)
I wrote a big program that use car and cdr, and do:
(map car (append (map caddr lists) (map cadr lists))
When lists is list of lists in the next format ((a (b) (c)) (d (e) (f))...(x (y) (z)))
When I did it I got one list (b c e f... y z)
(Note: b,c,...y,z is a list of numbers; a,d...x is a symbol)
But now, I found that b,c,...,y,z can be also empty list, and It gives the next error:
car: expects argument of type <pair>; given ()
What can I do?
Have you tried filtering away empty lists before your map? Something like this:
(map car (filter pair? (append (map caddr lists) (map cadr lists))))
The fundamental issue is that () is not a pair while car only acts on pairs. The simplest solution is just to get rid of everything that isn't a pair before mapping car onto the list; this is what (filter pair? ...) does.
Here's my shot. It's a straight solution, without using map, filter; in that way, I avoid going over and over the elements of the list constructing intermediate lists - except that I used a reverse operation for preserving the original order of the elements, if that's not an issue, remove reverse. For each element in the original list, if either the (b)... or (c)... part is empty, it's skipped.
(define (process lists)
(let loop ((l (reverse lists))
(a '())
(b '()))
(cond ((null? l)
(append b a))
((or (not (pair? (cadar l))) (not (pair? (caddar l))))
(loop (cdr l) a b))
(else
(loop (cdr l) (cons (caadar l) a) (cons (car (caddar l)) b))))))
I'm having trouble appending a list to another list. Below is my code. When I run (append '(1 2) '(3 4)) I get '(1 3 2 4).
I want the output to be '(1 2 3 4)
(define (append l m)
(if (null? l) '()
(cons (car l) (append m (cdr l)))))
Thanks
Well by switching the two lists around like that (switching the position of m and l when calling append recursively), you'll get the first item of the first list followed by the first item of the second list etc.
If you don't want that, you should keep l as the first argument and m as the second. So you get:
(define (append l m)
(if (null? l) '()
(cons (car l) (append (cdr l) m))))
Of course this doesn't work as wanted either, because now you only get the first list back and nothing is appended at all. What you need to do is, once the first list is fully appended (i.e. once l is empty), you need to return the second one as the tail, like this:
(define (append l m)
(if (null? l) m
(cons (car l) (append (cdr l) m))))
I came across this while studying myself. #sepp2k's answer is a fine piece of instruction guiding OP to correct their code to achieve a recursive definition of append. Here's an alternate definition of my-append using the higher-order function foldr:
(define (myappend xs ys)
(foldr cons ys xs))