Do iterative loop in scheme - scheme

New to scheme here and I'm having some trouble learning do loops. I am attempting to make a function that will take in an object and a vector, and then iterate through the vector until it find that object. When the object is found, it would then return a list containing all of the items in the vector before the object. My code is below. All it will return is how many iterations the do loop went through, instead of the list I want it to. If anyone could help me with the syntax, I would greatly appreciate it. Thanks! ( ideally this would return (1 2))
(define(vector-test-iterative X Vector)
(do ((i 0 (+ i 1))) (< i (vector-length Vector))
(if (eqv? X (vector-ref Vector i))
(= i (vector-length Vector))
(cons (vector-ref Vector i) (ls '())))
ls))
(vector-test-iterative '4 #(1 2 4 3 5))

If you're using Racket, then there's no need to use do, which was never popular among schemers anyway. There's a whole range of iterators -- look for for in the docs, and things that start with for. For example, your code boils down to
#lang racket
(define (values-before x vector)
(for/list ([y (stop-before (in-vector vector)
(lambda (y) (eqv? x y)))])
y))
(If you really want to use do, then you're missing a pair of parens around the test, and you should add a binding for the accumulator.)

A solution that uses a named loop. Cleaner (in my opinion!) than the do version and should work on any R5RS Scheme:
;; Extracts the sublist of `lst` up to `val`.
;; If `val` is not found, evaluates to an empty list.
(define (upto val lst)
(let loop ((res null) (lst lst))
(cond ((null? lst) null)
((eq? val (car lst)) (reverse res))
(else (loop (cons (car lst) res) (cdr lst))))))
;; Adapts the above procedure to work with vectors.
(define (vector-upto val vec)
(list->vector (upto val (vector->list vec))))
;; test
(vector-upto 6 #(1 2 3 4 5))
=> #0()
(vector-upto 5 #(1 2 3 4 5))
=> #4(1 2 3 4)
(vector-upto 3 #(1 2 3 4 5))
=> #2(1 2)
(vector-upto 1 #(1 2 3 4 5))
=> #0()

Related

How to invert the predicate here?

I have the following filter procedure:
; (2) filter
(define (filter test sequence)
; return a list of the elements that pass the predicate test
(let ((elem (if (null? sequence) nil (car sequence)))
(rest (if (null? sequence) nil (cdr sequence))))
(cond ((null? sequence) nil)
((test elem) (cons elem (filter test rest)))
(else (filter test rest)))))
And here would be an example of using it to return the even-numbered elements of a list:
(define even? (lambda (x) (= (modulo x 2) 0)))
(define sequence '(1 2 3 4 5 8 9 11 13 14 15 16 17))
(filter even? sequence)
; (2 4 8 14 16)
Is there a simple way to use the not test to invert the selection? For example, I thought the following might work:
(filter (not even?) sequence)
But it returns an error. I can define odd separately, of course:
(define odd? (lambda (x) (not (even? x))))
But I'm trying not to do this. Is there a way to write the odd procedure without defining it directly, but instead using the not directly like I'm trying to do above?
There is a complement function in Common Lisp that does what I think you are looking for. complement is a higher-order procedure that takes a procedure as its argument, and returns a procedure that takes the same arguments as the input procedure and performs the same actions, but the returned truth value is inverted.
Racket has a similar procedure, negate, and it is easy enough to implement this in Scheme:
(define (complement f)
(lambda xs (not (apply f xs))))
> (filter even? '(1 2 3 4 5))
(2 4)
> (filter (complement even?) '(1 2 3 4 5))
(1 3 5)
> (> 1 2 3 4 5)
#f
> ((complement >) 1 2 3 4 5)
#t
And in Racket:
scratch.rkt> (filter even? '(1 2 3 4 5))
'(2 4)
scratch.rkt> (filter (negate even?) '(1 2 3 4 5))
'(1 3 5)
scratch.rkt> (> 1 2 3 4 5)
#f
scratch.rkt> ((negate >) 1 2 3 4 5)
#t
The general answer to this is to simply compose not and the function you care about. Racket has a compose function which does this, but you can easily write a simple one yourself:
(define (compose-1 . functions)
;; simple-minded compose: each function other than the last must
;; take just one argument; all functions should return just one
;; value.
(define (compose-loop fns)
(cond
((null? fns)
(λ (x) x))
((null? (cdr fns))
(car fns))
(else
(λ (x) ((car fns) ((compose-loop (cdr fns)) x))))))
(compose-loop functions))
Making it efficient and more general takes more work of course.
Then you can define odd? (which is already defined of course):
(define odd? (compose-1 not even)
Or in fact define a more general CL-style complement function:
(define (complement f)
(compose-1 not f))
One option is to write an invert function which will curry things along (so the initial function still accepts one argument) until the final evaluation occurs:
(define invert (lambda (func) (lambda (x) (not (func x)))))
(define sequence '(1 2 3 4 5 6 8 9 11 13 14 15 16 17))
(filter (invert even?) sequence)
; (1 3 5 9 11 13 15 17)

How To Mutate Variables Scheme

I'm trying to sum a list using mutable objects for an assignment.letis used here to allow me to mutate x the total sum and counter. I'm not very well versed with scheme hence the use if statements for each number in the list lst:
(define lst (list 1 2 3 4 5))
(let mut ((counter 0))
(let ((x (car lst)))
(if (= counter 4)
x)
(if (= 0 counter)
(+ x (cadr lst)))
(if (= 1 counter)
(display (caddr lst)) ;test
(+ x (caddr lst)))
(if (= 2 counter)
(+ x (caddr lst)))
(set-car! lst (cdr lst))
(mut (+ counter 1))
)
)
however when I run the code I get an error
+: contract violation
expected: number?
given: (mcons 2 (mcons 3 (mcons 4 (mcons 5 '()))))
argument position: 1st
other arguments...:
However when I check (caddr lst) it returns a 3 as expected. My issue is why, when run, does caddr produce (mcons 2 (mcons 3 (mcons 4 (mcons 5 '())))) when applied to an + but when not applied it returns 3
I am using R5RS
edit: I have omitted some of the if statements for conciseness
Okay so I figured it out using a whole different implementation #molbdnilo was correct that my understanding was flawed.
here is my implementation if anyone else is struggling with this problem
(define (goMut)
(define mVar 0)
(define acc 0)
(define (accDo num)
(set! acc (+ num acc)))
(for-each (lambda (x) (set! mVar x) (accDo x))
(list 1 2 3 4 5))
acc
)
Using set! we can apply the value in the list to an external variable and mutate it as we iterate throughout the loop using the function accDo. Function template taken from SICP pg 107

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)

finding subsets of length N of a list in scheme

I wrote a function which finds all the subsets of a list already and it works. I'm trying to write a second function where I get all the subsets of N length, but it's not working very well.
This is my code:
(define (subset_length_n n lst)
(cond
[(empty? lst) empty]
[else (foldr (lambda (x y) (if (equal? (length y) n) (cons y x) x)) empty (powerset lst))]
))
where (powerset lst) gives a list of all the subsets.
Am I misunderstanding the purpose of foldr?
I was thinking that the program would go through each element of the list of subsets, compare the length to n, cons it onto the empty list if there the same, ignore it if it's not.
But (subset_length_n 2 (list 1 2 3)) gives me (list (list 1 2) 1 2 3) when I want (list (list 1 2) (list 1 3) (list 2 3))
Thanks in advance
When using foldr you don't have to test if the input list is empty, foldr takes care of that for you. And this seems like a job better suited for filter:
(define (subset_length_n n lst)
(filter (lambda (e) (= (length e) n))
(powerset lst)))
If you must, you can use foldr for this, but it's a rather contrived solution. You were very close to getting it right! in your code, just change the lambda's parameters, instead of (x y) write (y x). See how a nice indentation and appropriate parameter names go a long way toward writing correct solutions:
(define (subset_length_n n lst)
(foldr (lambda (e acc)
(if (= (length e) n)
(cons e acc)
acc))
empty
(powerset lst)))
Anyway, it works as expected:
(subset_length_n 4 '(1 2 3 4 5))
=> '((1 2 3 4) (1 2 3 5) (1 2 4 5) (1 3 4 5) (2 3 4 5))

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)

Resources