I have a (in theory) simple method in Scheme, that has to use recursion. The problem is that I can't seem to figure out the recursion part... I have a procedure that takes a 'pointer' and arbitrary many arguments, and I need to pass the arguments one by one to another method. Here is what I got so far:
(define (push-elements ptr . args)
(define (push-all ptr list)
(if (null? list)
'()
(ptr 'push-elements (car list))))
(push-all ptr list))
I know there is no recursion here, but I can't understand where to put it/how to do it. The thought is clear, inside 'push-all' I need to call:
(push-all ptr (cdr list))
If anyone could help me (and I would be very grateful for an explanation on how to go about making such a recursive method), that would be great.
It's helpful to consider the base case and each incremental case. If you try to push-all onto a stack but have no items, what should the result be? Just the stack. If you try to push-all onto a stack and you have multiple items, what's the result? Well, first you'd push the first of the items onto the stack, giving you a new stack. Then you can push-all the rest of the items onto that stack:
(define (push-all stack items)
(if (null? items)
stack
(let ((new-stack (cons (car items) stack))
(remaining-items (cdr items)))
(push-all new-stack remaining-items))))
(display (push-all '(1 2) '(a b c)))
;=> (c b a 1 2)
Now, your original version was variadic. That is, it accepts any number (well, greater than zero) of arguments because of the dotted arglist. That's fine, but it does mean that you'll need to use apply in setting up the recursive call:
(define (push-all stack . items)
(if (null? items)
stack
(let ((new-stack (cons (car items) stack))
(remaining-items (cdr items)))
(apply push-all new-stack remaining-items))))
(display (push-all '(1 2) 'a 'b 'c))
;=> (c b a 1 2)
Basically you are implementing a variant of for-each, which is like map just for the side effects:
(define (for-each procedure lst)
(let loop ((lst lst))
(if (null? lst)
'undefined-value
(begin
(procedure (car lst))
(loop (cdr lst))))))
(for-each display (list 1 2 3 4)) ; prints 1234
But you wanted to be able to specify the values as arguments so you need to change lst to be a rest argument:
(define (for-each-arg procedure . lst) ; changed to dotted list / rest here
(let loop ((lst lst))
(if (null? lst)
'undefined-value
(begin
(procedure (car lst))
(loop (cdr lst))))))
(for-each-arg display 1 2 3 4) ; prints 1234
If you want a more functional approach you are indeed making either a map or a fold. Perhaps a fold-left would be preferred:
(define (fold-args join init . lst)
(let loop ((acc init) (lst lst))
(if (null? lst)
acc
(loop (join (car lst) acc) (cdr lst)))))
(fold-args cons '() 1 2 3 4) ; ==> (4 3 2 1)
You can actually implement for-each-arg with this:
(define (for-each-arg procedure . lst)
(apply fold-args
(lambda (x acc)
(procedure x)
'undefined)
'undefined
lst))
(for-each-arg display 1 2 3 4) ; => undefined-value; prints 1234
Related
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 need to write a function that determines if the given list is a pair of elements. The program will simply respond #t if the list contains exactly two elements or #f if it does not, such that:
(zipper? '((a 1)(b 2))) => #t
and
(zipper? '((foo 100)(bar 2 3))) => #f
I'm still fairly new to Scheme so any help would be much appreciated!
Thanks!
It isn't clear if the "correct" input for the procedure is an arbitrary list or a two-element list. If it's strictly a two-element list, this will work:
(define (is-two-element-list? lst)
(and (list? lst)
(= (length lst) 2)))
(define (zipper? lst)
(and (is-two-element-list? lst)
(is-two-element-list? (first lst))
(is-two-element-list? (second lst))))
… And if it's an arbitrary-length list whose elements we want to check, this will work in Racket, using andmap:
(define (zipper? lst)
(andmap is-two-element-list? lst))
If you are not using Racket, then this solution using every will work in any interpreter with SRFIs:
(require srfi/1)
(define (zipper? lst)
(every is-two-element-list? lst))
Either way, notice that the trick was defining the is-two-element-list? procedure, which verifies the two-element-list property, after that we can apply it as needed.
Think of it this way. If the zipper list is '() then the answer is #t. If the zipper list is not '() then if the first element is two elements and the rest is another zipper?, then return #t.
(define (zipper? list)
(or (null? list)
(and (= 2 (length (car list)))
(zipper? (cdr list)))))
or maybe you mean:
(define (zipper? list)
(or (not (pair? list))
(and (= 2 (length list))
(zipper? (list-ref list 0))
(zipper? (list-ref list 1)))))
every element, at any level, has two elements.
> (zipper? '((a 1 2) '(b)))
#f
> (zipper? '(a b))
#t
> (zipper? '(((a (b b)) c) (1 2)))
#t
Let's say we have this list '( (4 (1 2)) (5 (5 5)) (7 (3 1)) (1 (2 3)))
I am trying to write smth in Scheme in order to get the second element for every element in the list.. So the result will look like '( (1 2) (5 5) (3 1) (2 3))
I have this code so far..
(define (second list1)
(if (null? (cdr list1))
(cdr (car list1))
((cdr (car list1))(second (cdr list1)))))
Here's a straightforward solution:
(define (seconds lst)
(map cadr lst))
In general, when you want to transform every element of a list, map is the way to go.
All you need to do is map the built-in function second onto the list lst:
(map second lst)
Your error is that you lack an operator, perhaps cons. If you look at the consequent:
((cdr (car list1))(second (cdr list1)))
So Scheme expects (cdr (car list)) to be a procedure since it's in operator position in the form, but since it isn't you get an error. In addition (cdr (car x)) == cdar wont take the second element in every element but the tail of each element. cadar is what you're lookig for.
(define (second list1)00+
(if (null? (cdr list1))
(cons (cadar list1) '())
(cons (cadar list1) (second (cdr list1)))))
It will fail for the empty list. To fix this you let the consequemt take care of every element and the base case only to stop:
(define (second list1)
(if (null? list1)
'()
(cons (cadar list1) (second (cdr list1)))))
The result for a list will be the same. There is a procedure called map. It supports several list arguments, but the implementation for one is:
(define (map fun lst)
(if (null? lst)
'()
(cons (fun (car lst)) (map fun (cdr lst)))))
Looks familiar? Both make a list based on each element, but map is generic. Thus we should try to make (fun (car lst)) do the same as (cadar lst).
(define (second lst)
(map cadr lst)) ; (cadr (car x)) == (cadar x)
There you have it. Chris beat me to it, but I'd like to comment one of the other answers that uses the abbreviation second. It's defined in racket/base and the library SRFI-1, but it's not mentioned in the last Scheme reports. I.e. some implementations might require an extra library to be imported for it to work.
I'm trying to write a code (function) using Scheme that:
Takes a list of any size as a parameter
Multiplies every number of the list together
Symbols should be skipped over
Values inside pairs should be included in multiplication
In other words, results should be as follows:
> (mult '(1 2 3))
6
> (mult '(1 2 x 3 4))
24
> (mult '(1 2 z (3 y 4)))
24 (mine gives me 2)
My code allows me to skip over the symbols and multiply everything. However, once I include a pair inside the list, it acts as though it isn't a number, therefore acting like it doesn't exist. Here's my code:
(define mult
(lambda (x)
(if (null? x)
1
(if(number? (car x))
(* (car x) (mult (cdr x)))
(mult(cdr x))))))
I've tried to use append when it finds a pair, but clearly I did it wrong... Any help on how I could get it to include the values inside a pair would be much appreciated.
i.e. '(1 2 y (3 z 4) = 1 * 2 * 3 * 4
You are nearly there, just missing the list? test:
(define (mult lst)
(if (null? lst)
1
(let ((ca (car lst)))
(cond
((number? ca) (* ca (mult (cdr lst))))
((list? ca) (* (mult ca) (mult (cdr lst))))
(else (mult (cdr lst)))))))
EDIT
He're an equivalent version without let:
(define (mult lst)
(cond
((null? lst) 1)
((number? (car lst)) (* (car lst) (mult (cdr lst))))
((cons? (car lst)) (* (mult (car lst)) (mult (cdr lst))))
(else (mult (cdr lst)))))
As you see, (car lst) is likely to be evaluated more than once, so I used let in the first version to avoid this.
It is a slightly advanced technique but this problem can easily be formulated as a tail recursive algorithm.
(define (mult lst)
(let multiplying ((lst lst) (r 1)) ; r is the multiplicative identity...
(if (null? lst)
r
(let ((next (car lst))
(rest (cdr lst)))
(multiplying rest (cond ((number? next) (* next r))
((list? next) (* (mult next) r))
(else r)))))))
> (mult '(1 2 3 a b (((((10)))))))
60
Using tail recursion has performance implications but, admittedly, it is not the first thing to learn - recursion is. However, in this case, because lists are often very long, avoiding a stack frame for each list element can be a dramatic savings; using tail calls avoids the stack frame.
im trying to write a function in Scheme where i accept a list and return all the different derangements (look below for definition) as a list of lists
derangement: A list where no item is in the same place as the original list
ex: '(a b c) -> '(cab)
any help is appreciated!
Compute all of the permutations of the input list and then filter out the ones that have an element in the same position as the input list. If you need more detail, leave a comment.
Edit 1:
Define (or maybe it's defined already? Good exercise, anyway) a procedure called filter that takes as its first argument a procedure p and a list l as its second argument. Return a list containing only the values for which (p l) returns a truthy value.
Define a procedure derangement? that tests if a list l1 is a derangement of l2. This will be handy when paired with filter.
The most obvious solution would be something like this:
(define filtered-permutations
(lambda (lst)
(filter
(lambda (permuted-list)
(deranged? permuted-list lst))
(permute lst))))
Since the number of derangements is considerably lower than then number of permutations, however, this is not very efficient. Here is a solution that mostly avoids generating permutations that are not derangements, but does use filter once, for the sake of simplicity:
(define deranged?
(lambda (lst1 lst2)
(if (null? lst1)
#t
(if (eq? (car lst1) (car lst2))
#f
(deranged? (cdr lst1) (cdr lst2))))))
(define derange
(lambda (lst)
(if (< (length lst) 2)
;; a list of zero or one elements can not be deranged
'()
(permute-helper lst lst))))
(define derange-helper
(lambda (lst template)
(if (= 2 (length lst))
(let ((one (car lst))
(two (cadr lst)))
(filter
(lambda (x)
(deranged? x template))
(list (list one two) (list two one))))
(let ((anchor (car template)))
(let loop ((todo lst)
(done '())
(result '()))
(if (null? todo)
result
(let ((item (car todo)))
(if (eq? item anchor)
;; this permutation would not be a derangement
(loop (cdr todo)
(cons item done)
result)
(let ((permutations
(map
(lambda (x)
(cons item x))
(derange-helper (append (cdr todo) done)
(cdr template)))))
(loop (cdr todo)
(cons item done)
(append result permutations)))))))))))