scheme function to filter a list - scheme

Write a scheme function that returns a list containing all elements of a given
list that satisfy a given predicate eg. (lambda (x) (< x 5)) '(3 9 5 8 2 4 7) => '(3 2 4)
Any hints how to begin about this ?

Basically you are creating filter.
(define (filter included? lst)
...)
You need to check if the argument has elements and if the first element is to be included or not. Including would involve cons-ing the first element to the recursing with the cdr with the same predicate while not including would not include consing but the exact same thing as the tail in a conse situation.
(filter odd? '(3 4))
; ==> (cons 3 (filter odd? '(4)))
(filter odd? '(4))
; ==> (filter odd? '())
(filter odd? '())
; ==> '()
Putting them together shows that (filter odd? '(3 4)) should produce the result of (cons 3 '())
Here is a skeleton of what I would have done:
(define (filter included? lst)
(cond ((null? lst) <??>)
((included? (car lst)) <??>) ; since it is not null? it has to have at least one element
(else <??>))) ; neither null? nor included? => skip

Related

How to define my own version of filter procedure in racket?

I am new in Racket and I was assigned to do my own filter procedure. It should work similar to the Racket filter procedure. Currently, my-filter has two arguments: the even procedure to check the items in the list, and a list of items.
So far, I have been only able to check whether the items in the list are even or not. my-filter is supposed to iterate through a list of numbers, retrieve the numbers that are even and save them in a second list. How can I iterate through the list and store the even numbers in the second list?
(define (my-filter f lst)
(if (empty? lst)
empty
(cons
(f (first lst))
(my-filter f (rest lst)))))
> (my-filter even? '(1 2 3 4 5 6))
'(#f #t #f #t #f #t)
There are three cases that you need to consider:
Input list is empty -> we're done.
Current element satisfies the predicate function -> add it to the output and continue with next element.
Current element doesn't satisfy the predicate function -> skip it and continue with next element.
You're mixing the last two cases into a single case. And notice that you must not add (f (first lst)) to the output, that's just the condition that we want to evaluate, we should add (first lst) instead. This is what I mean:
(define (my-filter f lst)
(cond ((empty? lst) empty)
((f (first lst))
(cons (first lst) (my-filter f (rest lst))))
(else (my-filter f (rest lst)))))
It works as expected:
(my-filter even? '(1 2 3 4 5 6))
=> '(2 4 6)

How to know what parameters a foldr's combine function should take?

For the built-in function foldr, I know the function blueprint is the following:
(foldr combine base alist)
combine is supposed to take in two parameters:
an item that foldr consumes
the result of applying foldr to the rest of alist
I cannot seem to understand how to put point #2 in parameter form ever. How did you do it?
combine is not a built-in function. I would have to code it myself based on the requirements.
Think of second parameter as the accumulated value so far. For example, if we are adding the elements, then acc is the sum of all the previous eles and we need to add the current element:
(foldr (lambda (ele acc) (+ ele acc))
0 ; we're adding numbers, so the base is 0
'(1 2 3 4 5))
=> 15
Another example - if we're copying the list, then acc contains the previous eles in the list (starting from the last one and going back from there) and we have to cons the current element at the head :
(foldr (lambda (ele acc) (cons ele acc))
'() ; we're creating a list, so the base is an empty list
'(1 2 3 4 5))
=> '(1 2 3 4 5)
The exact nature of acc depends on the problem to be solved, but you should be able get the idea from the previous examples.
Think of it as the result computed so far and that foldr iterates from end to beginning while a foldl iterates from beginning to end. It's easier to see if you look at a simple implementation of it:
(define (foldr1 f init lst)
(let r ((lst lst))
(if (null? lst)
init
(cons (f (car lst)) (r (cdr lst))))))
(foldr1 combine base '(1 2 3)) ; ==
(combine 1 (combine 2 (combine 3 base)))
(define (foldl1 f init lst)
(let r ((lst lst) (acc init))
(if (null? lst)
acc
(r (cdr lst) (f (car lst))))))
(foldl1 combine base '(1 2 3)) ; ==
(combine 3 (combine 2 (combine 1 base)))
Also note that the order or the arguments change in some implementations. Racket and SRFI-1 always have the accumulator as the last argument, but in R6RS the argument order changes for fold-left (but not fold-right):
#!r6rs
(import (rnrs))
;; swap argument order
(fold-left (lambda (acc e) (cons e acc)) '() '(1 2 3))
; ==> (3 2 1)

Print adjacent duplicates of a list (scheme)

I'm trying to create a function that returns the adjacent duplicates of a list, for example (dups '(1 2 1 1 1 4 4) should return the list (1 4).
This is the code I came up with so far:
(define (dups lst)
(if (equal? (car lst)(car(cdr lst)))
(cons(cdr lst) '())
(dups(cdr lst))))
This function doesn't return all the adjacent duplicates, it only returns the first adjacent duplicates!
How can I fix it so that it returns all the adjacent duplicates of a list?
Thank you.
Once your code finds a duplicate, it stops processing the rest of the list: when the if test is true, it yields (cons (cdr lst) '()). Whether or not it finds a duplicate, it should still be calling dups to process the rest of the list.
Also: if your list has no duplicates, it it going to run into trouble.
Here's a simpler solution than the others posted:
(define (dups lst)
(if (< (length lst) 2)
; No room for duplicates
'()
; Check for duplicate at start
(if (equal? (car lst) (cadr lst))
; Starts w/ a duplicate
(if (or (null? (cddr lst)) ; end of list
(not (equal? (car lst) (caddr lst)))) ; non-matching symbol next
; End of run of duplicates; add to front of what we find next
(cons (car lst) (dups (cdr lst)))
; Othersise keep looking
(dups (cdr lst)))
; No duplicate at start; keep looking
(dups (cdr lst)))))
Basically this boils down to only keeping the elements which are the same as the previous one, but different from the next.
Here's an example implementation using a named let.
(define (adj-dups lst)
(let loop ((lst (reverse (cons (gensym) lst)))
(e-2 (gensym))
(e-1 (gensym))
(acc '()))
(if (null? lst)
acc
(let ((e-0 (car lst)))
(loop (cdr lst)
e-1
e-0
(if (and (eqv? e-2 e-1) (not (eqv? e-1 e-0)))
(cons e-1 acc)
acc))))))
(gensym) comes in handy here because it's a convenient way to initialise the working variables with something that's different from everything else, and filling up the initial list with a dummy element that needs to be added so that we don't miss the last element.
Testing:
> (adj-dups '())
'()
> (adj-dups '(1 1 4 4 1 1))
'(1 4 1)
> (adj-dups '(1 1 1 1 1))
'(1)
> (adj-dups '(1 2 1 1 1 4 4))
'(1 4)
> (adj-dups '(2 3 3 4 4 4 5))
'(3 4)
The most straightforward way I can think of to tackle this is with an internal procedure with an extra variable to keep track what the prior element was and a boolean to track if the element was repeated. You can then do a mutual recurstion between the helper and main function to build the answer one duplicate element at a time.
(define (dups lst)
(define (dups-helper x repeat? L)
(cond ((null? L)
(if repeat?
(list x)
'()))
((equal? x (car L))
(dups-helper x #t (cdr L)))
(else
(if repeat?
(cons x (dups L))
(dups L)))))
(if (null? lst)
'()
(dups-helper (car lst) #f (cdr lst))))
(dups (list 1 1 4 4 5 6 3 3 1))
;Value 43: (1 4 3)

List of lengths from list of strings using map, filter, or fold-right

You are given a list of strings.
Generate a procedure such that applying this procedure to such a list
would result in a list of the lengths of each of the strings in the
input.
Use map, filter, or fold-right.
(lengths (list "This" "is" "not" "fun")) => (4 2 3 3)
(define lengths (lambda (lst) your_code_here))
I got stuck in the following code and I do not understand how can I use filter.
(define lengths
(lambda (lst)
(if (null? lst)
nil
(fold-right list (string-length (car lst)) (cdr lst)))))
This seems like a work for map, you just have to pass the right procedure as a parameter:
(define (lengths lst)
(map string-length lst))
As you should know, map applies a procedure to each of the elements in the input list, returning a new list collecting the results. If we're interested in building a list with the lengths of strings, then we call string-length on each element. The procedure pretty much writes itself!
A word of advice: read the documentation of the procedures you're being asked to use, the code you're writing is overly complicated. This was clearly not a job for filter, although fold-right could have been used, too. Just remember: let the higher-order procedure take care of the iteration, you don't have to do it explicitly:
(define (lengths lst)
(fold-right (lambda (x a)
(cons (string-length x) a))
'()
lst))
This looks like homework so I'll only give you pointers:
map takes a procedure and applies to to every element of a list. Thus
(define (is-strings lst)
(map string? lst))
(is-strings '("hello" 5 sym "89")) ; (#t #f #f #t)
(define (add-two lst)
(map (lambda (x) (+ x 2)) lst))
(add-two '(3 4 5 6)) ; ==> (5 6 7 8)
filter takes procedure that acts as a predicate. If #f the element is omitted, else the element is in the resulting list.
(define (filter-strings lst)
(filter string? lst))
(filter-strings '(3 5 "hey" test "you")) ; ==> ("hey" "you")
fold-right takes an initial value and a procedure that takes an accumulated value and a element and supposed to generate a new value:
(fold-right + 0 '(3 4 5 6)) ; ==> 18, since its (+ 3 (+ 4 (+ 5 (+ 6 0))))
(fold-right cons '() '(a b c d)) ; ==> (a b c d) since its (cons a (cons b (cons c (cons d '()))))
(fold-right - 0 '(1 2 3)) ; ==> -2 since its (- 1 (- 2 (- 3 0)))
(fold-right (lambda (e1 acc) (if (<= acc e1) acc e1)) +Inf.0 '(7 6 2 3)) ; ==> 2
fold-right has a left handed brother that is iterative and faster, though for list processing it would reverse the order after processing..
(fold-left (lambda (acc e1) (cons e1 acc)) '() '(1 2 3 4)) ; ==> (4 3 2 1)

Converting a list to a circular list in Chicken scheme?

In trying to find how to convert such a list, I came across
Scheme streams and circular lists. However, that answer requires features in Racket not available in Chicken scheme. Can Anyone point Me in the direction of how to do this in Chicken scheme instead? Or in a scheme-variant-neutral fashion?
If you can mutate the list, here's a standard way:
(define (make-circular lst)
; helper for finding the last pair in a list
(define (last-pair lst)
(if (null? (cdr lst))
lst
(last-pair (cdr lst))))
; special case: if the list is empty
(cond ((null? lst) '())
(else
; set the last pair to point to the head of the list
(set-cdr! (last-pair lst) lst)
lst)))
Be aware that the above will modify the input list. Other than that, it works as expected:
(make-circular '(1 2 3 4 5))
=> #0=(1 2 3 4 5 . #0#)
(car (cdr (cdr (cdr (cdr (cdr (make-circular '(1 2 3 4 5))))))))
=> 1
It is pretty simple when you use SRFIs:
(use srfi-1)
(define l '(1 2 3 4))
(apply circular-list l)

Resources