Optional keyword argument and multiple arguments exercise - scheme

I have to write a function pow-increase which accepts an arbitrary number of arguments and one optional parameter. For each argument, it must calculate its power to some number, which is incremented for every argument, starting with the number 2, or, if the optional keyword argument is supplied, starts with that number.
Example:
> (pow-increase 2 2 2 2) ; 2^2 2^3 2^4 2^5
'(4 8 16 32)
> (pow-increase #start: 1 2 2 2 2) ; 2^1 2^2 2^3 2^4
'(2 4 8 16)
I've already written the function for the first call:
(define pow-increase
(lambda argList
(let* ([len (length argList)]
[exponents (range 2 (+ len 2) 1)])
(map (lambda (x) (expt (car x) (car(cdr x)))) (zip argList exponents)))))
Now I'd like to write the second version of the function (for the second call) but I don't know how to pass simultaneously an arbitrary number of arguments and an optional keyword argument. I've read here the syntax for optional arguments is: [optParamName value].
Thank you in advance for your help.

I'd go for
(define (pow-increase #:start (start 2) . lst)
(for/list ((e (in-list lst)) (i (in-naturals start)))
(expt e i)))
testing
> (pow-increase 2 2 2 2)
'(4 8 16 32)
> (pow-increase #:start 1 2 2 2 2)
'(2 4 8 16)
Note how elegant the code can become if you use Racket's for loops. If you want to stay with your initial version, the modification would be:
(define pow-increase
(lambda (#:start (start 2) . argList)
(let* ([len (length argList)]
[exponents (range start (+ len start) 1)])
(map (lambda (x) (expt (car x) (car (cdr x)))) (zip argList exponents)))))
but even then, you can simplify by getting rid of zip since map allows for more than one list:
(define pow-increase
(lambda (#:start (start 2) . argList)
(let* ([len (length argList)]
[exponents (range start (+ len start) 1)])
(map expt argList exponents))))

Related

The apply function in SICP/Scheme

I've asked a few questions here about Scheme/SICP, and quite frequently the answers involve using the apply procedure, which I haven't seen in SICP, and in the book's Index, it only lists it one time, and it turns out to be a footnote.
Some examples of usage are basically every answer to this question: Going from Curry-0, 1, 2, to ...n.
I am interested in how apply works, and I wonder if some examples are available. How could the apply procedure be re-written into another function, such as rewriting map like this?
#lang sicp
(define (map func sequence)
(if (null? sequence) nil
(cons (func (car sequence)) (map func (cdr sequence)))))
It seems maybe it just does a function call with the first argument? Something like:
(apply list '(1 2 3 4 5)) ; --> (list 1 2 3 4 5)
(apply + '(1 2 3)) ; --> (+ 1 2 3)
So maybe something similar to this in Python?
>>> args=[1,2,3]
>>> func='max'
>>> getattr(__builtins__, func)(*args)
3
apply is used when you want to call a function with a dynamic number of arguments.
Your map function only allows you to call functions that take exactly one argument. You can use apply to map functions with different numbers of arguments, using a variable number of lists.
(define (map func . sequences)
(if (null? (car sequences))
'()
(cons (apply func (map car sequences))
(apply map func (map cdr sequences)))))
(map + '(1 2 3) '(4 5 6))
;; Output: (5 7 9)
You asked to see how apply could be coded, not how it can be used.
It can be coded as
#lang sicp
; (define (appl f xs) ; #lang racket
; (eval
; (cons f (map (lambda (x) (list 'quote x)) xs))))
(define (appl f xs) ; #lang r5rs, sicp
(eval
(cons f (map (lambda (x) (list 'quote x))
xs))
(null-environment 5)))
Trying it out in Racket under #lang sicp:
> (display (appl list '(1 2 3 4 5)))
(1 2 3 4 5)
> (display ( list 1 2 3 4 5 ))
(1 2 3 4 5)
> (appl + (list (+ 1 2) 3))
6
> ( + (+ 1 2) 3 )
6
> (display (appl map (cons list '((1 2 3) (10 20 30)))))
((1 10) (2 20) (3 30))
> (display ( map list '(1 2 3) '(10 20 30) ))
((1 10) (2 20) (3 30))
Here's the link to the docs about eval.
It requires an environment as the second argument, so we supply it with (null-environment 5) which just returns an empty environment, it looks like it. We don't actually need any environment here, as the evaluation of the arguments has already been done at that point.

Looking for clarification on 'map' in Racket

new to stackoverflow and new to racket. I've been studying racket using this documentation: https://docs.racket-lang.org/reference/pairs.html
This is my understanding of map:
(map (lambda (number) (+ 1 number))'(1 2 3 4))
this assigns '(1 2 3 4) to variable number ,then map performs (+ 1 '(1 2 3 4)).
but when I see things like:
(define (matrix_addition matrix_a matrix_b)
(map (lambda (x y) (map + x y)) matrix_a matrix_b))
I get very lost. I assume we're assigning two variables x and y, then performing (map + x y),but I don't understand what or how (map + x y) works.
Another one I'm having trouble with is
(define (matrix_transpose matrix_a)
(apply map (lambda x x) matrix_a))
what does (lambda x x) exactly do?
Thank you so much for clarifying. As you can see I've been working on matrix operations as suggested by a friend of mine.
Here is one way to think about map:
(map f (list 1 2 3))
; computes
(list (f 1) (f 2) (f 3))
and
(map f (list 1 2 3) (list 11 22 33))
; computes
(list (f 1 11) (f 2 22) (f 3 33))
So your example with + becomes:
(map + (list 1 2 3) (list 11 22 33))
; computes
(list (+ 1 11) (+ 2 22) (+ 3 33))
which is (list 12 24 36).
In the beginning it with be clearer to write
(define f (lambda (x y) (+ x y)))
(map f (list 1 2 3) (list 11 22 33)))
but when you can get used to map and lambda, the shorthand
(map (lambda (x y) (+ x y)) (list 1 2 3) (list 11 22 33)))
is useful.
this assigns '(1 2 3 4) to variable number ,then map performs (+ 1 '(1 2 3 4)).
No, that's not what it does. map is a looping function, it calls the function separately for each element in the list, and returns a list of the results.
So first it binds number to 1 and performs (+ 1 number), which is (+ 1 1). Then it binds number to 2 and performs (+ 1 number), which is (+ 1 2). And so on. All the results are collected into a list, so it returns (2 3 4 5).
Getting to your matrix operation, the matrix is represented as a list of lists, so we need nested loops, which are done using nested calls to map.
(map (lambda (x y) (map + x y)) matrix_a matrix_b)
The outer map works as follows: First it binds x and y to the first elements of matrix_a and matrix_b respectively, and performs (map + x y). Then it binds x and y to the second elements of matrix_a and matrix_b, and performs (map + x y). And so on for each element of the two lists. Finally it returns a list of all these results.
The inner (map + x y) adds the corresponding elements of the two lists, returning a list of the sums. E.g. (map + '(1 2 3) '(4 5 6)) returns (5 7 9).
So all together this creates a list of lists, where each element is the sum of the corresponding elements of matrix_a and matrix_b.
Finally,
what does (lambda x x) exactly do?
It binds x to the list of all the arguments, and returns that list. So ((lambda x x) 1 2 3 4) returns the list (1 2 3 4). It's basically the inverse of apply, which spreads a list into multiple arguments to a function.
(apply (lambda x x) some-list)
returns a copy of some-list.
this assigns '(1 2 3 4) to variable number ,then map performs (+ 1 '(1 2 3 4)).
If it was that simple why the need for map. You could just do (+ 1 '(1 2 3 4)) directly. Here is an implementation of map1 which is map that can only have one list argument:
(define (map1 fn lst)
(if (empty? lst)
empty
(cons (fn (first lst))
(map1 f (rest lst)))))
And what it does:
(map1 add1 '(1 2 3))
; ==> (cons (add1 1) (cons (add1 2) (cons (add1 3) empty)))
; same as (list (add1 1) (add1 2) (add1 3))
The real map accepts any number of list arguments and then expect the element function to take as many elements that there are list arguments. eg.
(map (lambda (l n s) (list l n s)) '(a b c) '(1 2 3) '($ % *))
; ==> ((a 1 $) (b 2 %) (c 3 *))
A very cool way to do this without knowing the number of elements is unzip
(define (unzip . lst)
(apply map list lst))
(unzip '(a b c) '(1 2 3) '($ % *))
; ==> ((a 1 $) (b 2 %) (c 3 *))
So apply flattens the call to (map list '(a b c) '(1 2 3) '($ % *)) and list takes arbitrary elements so it ends up working the same way as th eprevious example, but it will also work for other dimentions:
(unzip '(a b c d) '(1 2 3 4))
; ==> ((a 1) (b 2) (c 3) (d 4))
The first argument of map is a function. This function can require one or more arguments. Followed by the function in the arguments lists are one or more lists.
map loops from first to the last element of the lists in parallel.
And feeds therefore the i-th position of each list as arguments to the function
and collects the result into a results list which it returns.
Now three short examples which would make it clear to you how map goes through the lists:
(map list '(1 2 3))
;; => '((1) (2) (3))
(map list '(1 2 3) '(a b c))
;; => '((1 a) (2 b) (3 c))
(map list '(1 2 3) '(a b c) '(A B C))
;; => '((1 a A) (2 b B) (3 c C))

Creating an evaluate function in racket

Example of what function should do:
(list 3 4 6 9 7) ←→ 3x^4 + 4x^3 + 6x^2 + 9x + 7
What I have so far:
(define (poly-eval x numlist)
(compute-poly-tail x numlist 0 0))
(define (compute-poly-tail xn list n acc)
(cond
[(null? list) acc]
[else (compute-poly-tail (first list) (rest list)
(+ acc (* (first list) (expt xn n))) (+ n 1))]))
(check-expect(poly-eval 5 (list 1 0 -1)) 24)
(check-expect(poly-eval 0 (list 3 4 6 9 7)) 7)
(check-expect(poly-eval 2 (list 1 1 0 1 1 0)) 54)
Expected results:
(check-expect(poly-eval 5(list 1 0 -1)) 24)
(check-expect(poly-eval 0 (list 3 4 6 9 7))7)
(check-expect(poly-eval 2 (list 1 1 0 1 1 0)) 54)
I am getting a run-time error. Can someone spot what I am doing wrong. I don't know why I am getting these results.
There are a couple of errors in the code:
You need to process the coefficient's list in the correct order, corresponding to their position in the polynomial! you can either:
reverse the list from the beginning and process the coefficients from right to left (simpler).
Or start n in (sub1 (length numlist)) and decrease it at each iteration (that's what I did).
The order and value of the arguments when calling the recursion in compute-poly-tail is incorrect, check the procedure definition, make sure that you pass along the values in the same order as you defined them, also the first call to (first list) doesn't make any sense.
You should not name list a parameter, this will clash with the built-in procedure of the same name. I renamed it to lst.
This should fix the issues:
(define (poly-eval x numlist)
(compute-poly-tail x numlist (sub1 (length numlist)) 0))
(define (compute-poly-tail xn lst n acc)
(cond
[(null? lst) acc]
[else (compute-poly-tail xn
(rest lst)
(- n 1)
(+ acc (* (first lst) (expt xn n))))]))
It works as expected:
(poly-eval 5 (list 1 0 -1))
=> 24
(poly-eval 0 (list 3 4 6 9 7))
=> 7
(poly-eval 2 (list 1 1 0 1 1 0))
=> 54
Build power coefficient and unknown list than use map function.
; 2*3^1+4*3^0
; input is 3 and '(2 4)
; we need '(3 3) '(2 4) '(1 0)
; use map expt build '(3^1 3^0)
; use map * build '(2*3^1 4*3^0)
; use foldr + 0 sum up
(define (poly-eval x coefficient-ls)
(local ((define power-ls (reverse (build-list (length coefficient-ls) values)))
(define unknown-ls (build-list (length coefficient-ls) (λ (i) x))))
(foldr + 0 (map * coefficient-ls (map expt unknown-ls power-ls)))))

Multiple bindings in a for loop

So, the Racket (6.5) documentation says you can bind several ids at once:
(for ([(i j) #hash(("a" . 1) ("b" . 20))])
(display (list i j)))
Bu-u-ut I can't figure out / find an example of how to do this with manually constructed data:
(define a '(1 2 3 4 5))
(define b '(10 20 30 40 50))
(for ([(i j) (map list a b)])
(display (list i j)))
explodes with
result arity mismatch;
expected number of values not received
expected: 2
received: 1
from:
in: local-binding form
values...:
What am I missing?
This
(for ([(i j) #hash(("a" . 1) ("b" . 20))])
(display (list i j)))
is short for
(for ([(i j) (in-hash #hash(("a" . 1) ("b" . 20)))])
(display (list i j)))
Now in-hash returns two values at a time, so (i j)
will be bound to the two values.
On the other hand, this:
(for ([(i j) (map list a b)])
(display (list i j)))
is short for
(for ([(i j) (in-list (map list a b))])
(display (list i j)))
and in-list will return one element at a time (in you example
the element is a list). Since there are two names in (i j)
and not just one, an error is signaled.
Follow Toxaris' advice in in-parallel.
UPDATE
The following helper make-values-sequence shows
how to create a custom sequence, that repeatedly
produces more than one value.
#lang racket
(define (make-values-sequence xss)
; xss is a list of (list x ...)
(make-do-sequence (λ ()
(values (λ (xss) (apply values (first xss))) ; pos->element
rest ; next-position
xss ; initial pos
(λ (xss) (not (empty? xss))) ; continue-with-pos?
#f ; not used
#f)))) ; not used]
(for/list ([(i j) (make-values-sequence '((1 2) (4 5) (5 6)))])
(+ i j))
Output:
'(3 9 11)
In this example, you can use separate clauses to bind i and j:
(for ([i (list 1 2 3 4 5)]
[j (list 10 20 30 40 50)])
(display (list i j)))
More generally, you can use in-parallel to create a single sequence of multiple values from multiple sequences of single values:
(for ([(i j) (in-parallel (list 1 2 3 4 5)
(list 10 20 30 40 50))])
(display (list i j)))
Both solutions print (1 10)(2 20)(3 30)(4 40)(5 50).

Scheme operation on a function

Is it possible to do an operation on a previous function, i have a list of values say (1,2,3,4,5), first function needs to multiply them by 2, while 2nd function adds 1 to result of previous function, so first we would get (2,4,6,8,10), and then (3,5,7,9,11) i got this, function g does extra work, is it possible nstead of doing operations on the element do it on function F or results from function F
#lang racket
(define test (list 1 1 2 3 5))
(define (F)
(map (lambda (element) (* 2 element))
test))
(define (G)
(map (lambda (element) (+ 1 (* 2 element)))
test))
First you need to correctly define your procedures to take a list parameter (called lst in this case):
(define (F lst)
(map (lambda (e) (* 2 e)) lst))
(define (G lst)
(map add1 lst))
Then
> (F '(1 2 3 4 5))
'(2 4 6 8 10)
> (G '(2 4 6 8 10))
'(3 5 7 9 11)
or, if you need to combine both procedures:
> (G (F '(1 2 3 4 5)))
'(3 5 7 9 11)
This is a follow-up to your previous question. As stated in my answer there, you should pass the right parameters to the functions - in particular, pass the input lists as parameter, so you can use the result from one function as input for the next function:
(define test (list 1 1 2 3 5))
(define (multiply-list test)
(map (lambda (element) (* 2 element))
test))
(define (add-list test)
(map (lambda (element) (+ 1 element))
test))
Now, if we want to add one to each element in the input list:
(add-list test)
=> '(3 3 5 7 11)
Or if we want to multiply by two each element in the input list:
(multiply-list test)
=> '(2 2 4 6 10)
And if we want to add one first, then multiply by two we can chain the functions! the result from one becomes the input for the other, and the final result will be as follows:
(multiply-list (add-list test))
=> '(6 6 10 14 22)
NB! You have tagged scheme but you use racket (the language). Not all of my examples will work in scheme.
Yes! you even do it yourself in your definition of G where you add a value and the result of a multiplication.
Its possible to chain map
(map f3 (map f2 (map f1 lst)))
Thus if you instead make a function that takes a list and doubles it:
(define (list-double lst)
(map (lambda (x) (* x 2)) lst))
You can chain it to quadruple it:
(define (list-quadruple lst)
(list-double (list-double lst)))
Now it's not optimal to chain map if you can avoid it. Instead you can compose the procedures together:
(define (double x) (* x 2))
(define (list-quadrouple lst)
(map (compose1 double double) lst))
compose1 here is the same as making a anonymous function where you chain the arguments. Eg. the last would be (lambda (x) (double (double x))). A more complex one compose can do more than one value between procedures. eg. (compose + quotient/remainder)

Resources