Scheme higher-order function - scheme

I try to create a procedure that converts a binary number in a list to a string. Sample output: (binary->string '(1 1 0 1 0 0)) should give "110100".
(define reduce
(lambda (op base x) ;passing by name
(if (null? x)
base
(op (car x) (reduce op base (cdr x))))))
And here is my code:
(define (binary->string lst)
(reduce (number->string lst list->string )))
I know it is wrong but it is the best I came out with so far. Please help me to make it work properly.

Before I will show you solution, here is some advice: when you write Racket code, you should check correct number of arguments and their type.
In this case, you know that reduce needs (op base x), that are three arguments, but when you use some unknown function, like number->string, there is Racket documentation and after short search, you fill find number->string entry:
(number->string z [radix]) → string?
z : number?
radix : (or/c 2 8 10 16) = 10
Returns a string that is the printed form of z (see Printing Numbers) in the base specified by radix. If z is inexact, radix must be 10, otherwise the exn:fail:contract exception is raised.
Examples:
(number->string 3.0)
"3.0"
(number->string 255 8)
"377"
As you can see, you can call this function with one or two arguments, but in both cases, they have to be number. But with this call (number->string lst list->string ), you are passing list and procedure- so I can already tell that your code will end with error. And when you try to call your function in REPL, exactly this happens:
> (binary->string '(1 0 0 1))
. . number->string: contract violation
expected: number?
given: '(1 0 0 1)
argument position: 1st
other arguments...:
After you carefully check what did you write, you should be able to predict what will happen, before you even run your code.
Here is solution:
(define (binary->string lst)
(reduce string-append "" (map number->string lst)))
You will use map to create string from each number in list, then you join these strings with your reduce and string-append.

Related

Understanding how a sequence works

I have the following accumulate function:
; accumulate
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence) (accumulate op initial (cdr sequence)))))
I'm trying to write a length function to get the length of a sequence using the accumulate function.
For the function to plug into accumulate, why is it (+ y 1) instead of (+ x 1) ? That's the part I can't figure out:
(define (length sequence)
(accumulate (lambda (x y) (+ x 1)) ; wrong
0
sequence))
(define (length sequence)
(accumulate (lambda (x y) (+ y 1)) ; correct
0
sequence))
Your problem is that x and y doesn't tell you anything what it is. However if you look at accumulate you can see how op is called:
(op (car sequence) ; first argument is the element
(accumulate op initial (cdr sequence))) ; second argument is the accumulated value
While it doesn't really look that way Imagine that the second argument is calling accumulate on the empty sequence. Then you get this:
(op (car sequence)
initial)
So lets make length:
(define (length sequence)
(accumulate (lambda (element initial)
;; initial is often also called acc / accumulator
(+ 1 initial))
0
sequence))
So the answer is that the first argument is the individual element while the second is either the initial value (0) or the previous calculated value which is 0 with as many 1 added as the tail of the sequence had. Thus a number. WHy you don't use the first argument is that you can't really use "a" or whatever the list contains to count elements since you need to just count them not use them as values. If you use the first argument and it happens to be strings what is (+ "a" 0) supposed to help in finding out that the list has length 1?
If you use (lambda (x y) (+ x 1)) as op, then your length (or to be precise, the accumulate) function will not use the result of the recursive calls to the accumulate function. It will essentially only do one computation, (+ x 1) ,where x is (car sequence), the first element of sequence -- and this one computation may or may not even make sense, depending on whether or not x is a number, and even if it did the answer would be wrong.
On the other hand, if op is (lambda (x y) (+ y 1)), then your function will replace
(op (car sequence) (accumulate op initial (cdr sequence)))
with
(+ (accumulate op initial (cdr sequence)) 1)
The recursion bottoms out with the computation (+ 0 1), so you ultimately get the length of the list, when each of the nested recursive calls to accumulate return the length of the sub-lists to their calling functions.

Alternating Sum Using Foldr/Foldl (Racket)

Back again with another Racket question. New to higher order functions in general, so give me some leeway.
Currently trying to find the alternating sum using the foldr/foldl functions and not recursion.
e.g. (altsum '(1 3 5 7)) should equal 1 - 3 + 5 - 7, which totals to -4.
I've thought about a few possible ways to tackle this problem:
Get the numbers to add in one list and the numbers to subtract in another list and fold them together.
Somehow use the list length to determine whether to subtract or add.
Maybe generate some sort of '(1 -1 1 -1) mask, multiply respectively, then fold add everything.
However, I have no clue where to start with foldl/foldr when every operation is not the same for every item in the list, so I'm having trouble implementing any of my ideas. Additionally, whenever I try to add more than 2 variables in my foldl's anonymous class, I have no idea what variables afterward refer to what variables in the anonymous class either.
Any help or pointers would be greatly appreciated.
We can leverage two higher-order procedures here: foldr for processing the list and build-list for generating a list of alternating operations to perform. Notice that foldr can accept more than one input list, in this case we take a list of numbers and a list of operations and iterate over them element-wise, accumulating the result:
(define (altsum lst)
(foldr (lambda (ele op acc) (op acc ele))
0
lst
(build-list (length lst)
(lambda (i) (if (even? i) + -)))))
It works as expected:
(altsum '(1 3 5 7))
=> -4
Your idea is OK. You can use range to make a list of number 0 to length-1 and use the oddness of each to determine + or -:
(define (alt-sum lst)
(foldl (lambda (index e acc)
(define op (if (even? index) + -))
(op acc e))
0
(range (length lst))
lst))
As an alternative one can use SRFI-1 List Library that has fold that allows different length lists as well as infinite lists and together with circular-list you can have it alterate between + and - for the duration of lst.
(require srfi/1) ; For R6RS you import (srfi :1)
(define (alt-sum lst)
(fold (lambda (op n result)
(op result n))
0
(circular-list + -)
lst))
(alt-sum '(1 3 5 7))
; ==> -4

How to multiply a list in scheme?

New to scheme but trying to learn the basics.
Let's say I passed a list in as a parameter and I wanted to multiply each element by -1. Right now I have this:
(define (negative b)
(* (car b) -1 )))
Which returns the first element as -1 * that element
So in this case giving it (negative '(5 1 2 3)) returns -5.
But lets say I want it to return
-5 -1 -2 -3
How would I go about making the rest of the list negative? Using cdr recursively?
Do it recursively.
(define (negative l)
(if (null? l)
'()
(cons (* (car l) -1)
(negative (cdr l)))))
If the list is empty, this just returns an empty list, as the base case.
Otherwise, it calculates -1 * the first element, the negative of the rest of the list, and combines them to produce the result.
The purpose of your exercise may be for you to code up your own map procedure, in which case that's fine. But if not, use scheme's built in 'map' procedure which is intended for just this kind of purpose.
'map' has been available at least since R4RS (that is, a long time ago) and possibly earlier.
by using map. If you want it returned as list.
It would be like this
(define negative
(lambda (b)
(map - b)))
Map is going through list b, and apply procedure "-" to each number in list
If you want to return as single numbers not in list you apply values on the list.
(define negative1
(lambda (b)
(apply values (map - b))))
Edit: I saw that you are asking for recursive solution, which would go like this
(define negative1
(lambda (b)
(if (null? b)
'()
(cons (- (car b)) (negative1 (cdr b))))))

contract violation in my implementation of "map"

I'm beginning in Scheme (actually, Racket with DrRacket) and I want to practice by implementing a map function (apply a function to all elements of a list), but there's something wrong that I don't understand.
(I have, aside from my imperative background, a basic knowledge of haskell)
I want to translate the following piece of haskell (Just to show the algorithm) :
map f [] = []
map f x:xs = (f x) : (map f xs)
Here's my code :
(define (map f xs)
(if (= xs '()) '() ; if list is empty, return empty list
(cons (f (car xs)) (map f (cdr xs))))
)
To test it, I used this :
(define (testFunction x) (+ x 1))
(define testList '(1 2 3 4 5))
(map testFunction testList)
And I get the following error :
=: contract violation
expected: number ?
given : '(1 2 3 4 5)
argument position: 1st
other arguments...:
which highlights the predicate (= xs '())
Any tips ?
The = function is specifically for equality between numbers. It has special handling for numeric values by handling comparisons between exact and inexact numbers. In general, though, for non-numeric equality, you should use the equal? predicate:
> (equal? '() '())
#t
In this particular case, as mentioned by Raghav, you can also use empty? or null? to test for the empty list (the empty? predicate is just an alias for null?).
Wow - a few others already beat me to it, but I'll share my answer, anyways.
Your issue stems from your use of = to test list emptiness.
From the = in the docs:
Returns #t if all of the arguments are numerically equal, #f
otherwise.
In order to get your program working, I'd suggest using equal? to test the two lists for equality or, better yet, use empty? or null? to test if xs is an empty list. (I hope you don't take offense, but I've also massaged the code into what's (arguably) more idiomatic Scheme).
(define (mymap f xs)
(if (empty? xs)
xs
(cons
(f (car xs))
(mymap f (cdr xs)))))
(define (test-function x) (+ x 1))
(define test-list (list 1 2 3 4))
(mymap test-function test-list)
If you're using DrRacket, then for that condition, simply use (empty?):
(if (empty? xs)
xs ; because xs is empty
...)

(scheme) Verify if an element in one list is in the second list with do cicle

How do we verify in scheme with the do cicle, if an element of the first list is in the second?
The do loop in racket has an interesting structure:
(do ([id init-expr step-expr-maybe] ...)
(stop?-expr finish-expr ...)
expr ...)
The documentation for r5rs provides an example:
(let ((x '(1 3 5 7 9)))
(do ((x x (cdr x))
(sum 0 (+ sum (car x))))
((null? x) sum)))
That statement returns 25, the sum of the elements of the loop. The x in the do loop is initialized to the x in the let, and then iteratively set to the cdr of itself each time through the loop. sum is initialized to 0, and accumulates the value of the car of x each time through. The stopping condition is when the iteration variable is empty, and the return value is the sum.
Ok, aside from the racket preference of square brackets, this looks good. There's a do loop and a list. The loop does something over that list. We can use that to write a function that finds a specific atom in a list (using the racket brackets):
(define (find5 lst)
(do ([x lst (rest x)]
[found #f (or found (eq? 5 (first x)))])
((null? x) found)))
Instead of initializing and adding the value sum, I or into found. Also, I prefer first and rest over car and cdr and define them myself when they don't exist. The way this function works should follow from the explanation of the example.
(find5 '(1 2 3 4 6))
Gives #f, as expected. Similarly:
(find5 '(1 2 3 4 5 6))
Gives #t.
Are you able to generalize finding a specific element in a list with a do loop into your specific question?

Resources