I am new to Racket programming, and I am working on a problem where I am given a list of numbers, and I have to make a list of list, of different combinations of numbers.
Something like :
(combine (list 3 1 2)) => (list
(list 31 32 33)
(list 21 22 3)
(list 11 12 13))
How do I achieve this in Racket?
Thank You
Just play with iterators and comprehension to implement a cartesian product that returns lists of lists, and a bit of arithmetic to obtain the right results. Try this:
(for/list ((i '(3 2 1)))
(for/list ((j '(1 2 3)))
(+ (* 10 i) j)))
Or alternatively, using more standard constructs (available in student languages):
(map (lambda (i)
(map (lambda (j)
(+ (* 10 i) j))
'(1 2 3)))
'(3 2 1))
Either way, it works as expected:
=> '((31 32 33) (21 22 23) (11 12 13))
Related
I want to define a function in Scheme that will compute the outer product of two vectors.
for example:
(outerProduct '(1 2 3) '(4 5))
the output is supposed to be the following matrix:
((4 5) (8 10) (12 15))
How can I achieve that?
Note that collections used in your example aren't vectors, but lists. But this code with two nested for/lists will work for both:
(define (outer-product v1 v2)
(for/list ((e1 v1))
(for/list ((e2 v2))
(* e1 e2))))
Examples:
> (outer-product '(1 2 3) '(4 5))
'((4 5) (8 10) (12 15))
> (outer-product (vector 1 2 3) (vector 4 5))
'((4 5) (8 10) (12 15))
You can also do it with map if you don't want to use Racket-specific constructs (Assuming you're working with lists like in your code and not vectors like the subject line (Maybe you're thinking of vectors in the math sense, not the scheme sense?); though Racket has a vector-map too so it's easy to adapt:
(define (outerProduct l1 l2)
(map (lambda (x) (map (lambda (y) (* x y)) l2)) l1))
Example:
> (outerProduct '(1 2 3) '(4 5))
'((4 5) (8 10) (12 15))
Or using the math/matrix library that comes with Racket:
(require math/matrix)
(define (outerProduct l1 l2)
(let ((m1 (->col-matrix l1))
(m2 (->row-matrix l2)))
(matrix->list* (matrix* m1 m2))))
(This is a better option if you use its matrix type directly instead of converting to and from lists and are also doing other stuff with the values; also the docs suggest using typed Racket for best performance)
(define outerprod
(lambda (a b)
(map (lambda (a)
(map (lambda(b) (* a b))
b))
a )))
1 ]=> (outerprod '(1 2 3) '(4 5))
;Value: ((4 5) (8 10) (12 15))
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.
I have only just started to learn scheme and were asked to implement the quick-sort algorithm in scheme, but we are not allow to use any imperative features like set! and we are not allowed to use filter
I have tried to come up with my own algorithm with this in mind, but I can't seem to avoid the use of set! for updating a list:
(define quicksort
(lambda (L)
(cond
[(or (null? L) (null? (cdr L))) L]
[else (let ((pivot (car L)) (small '()) (large '()))
(do ((i (- (length L) 1) (- i 1)))
((= i 0))
(if (< (list-ref L i) pivot)
(set! small (cons (list-ref L i) small))
(set! large (cons (list-ref L i) large))))
(append (quicksort small) (list pivot) (quicksort large)))])))
This code works, but is there any way of updating the lists small and large without the use of set?
If you cannot use set!, you cannot mutate lists. You are being asked to do this functionally, without any mutation. Instead of modifying a list in-place, build up smaller, partially-sorted lists and then combine them while preserving the sort.
To be fair Quicksort is an in place algorithm and many would state replacing the vectors with lists will change it enough to no longer bee quicksort. I'll ignore this at the moment.
Split large stuff in smaller chunks of code. This way you can test each step:
(segment 5 '(5 1 1 3 8 6 4 9 8 5 3 5 3 8 6))
; ==> ((1 1 3 4 3 3) (5 5) (8 6 9 8 8 6))
Of course you make the simple tests first:
(segment 5 '(5)) ; ==> (() (5) ())
(segment 5 '(5 1)) ; ==> ((1) (5) ())
(segment 5 '(5 8)) ; ==> (() (5) (8))
(segment 5 '(5 8 1 5)) ; ==> ((1) (5 5) (8))
The order of the results in the sub list is not important. eg. the result ((3 3 4 3 1 1) (5 5) (6 8 8 9 6 8)) is equally as sufficient and most probably easier to do.
With that made quicksort by first checking if it is a less than 2 element list eg. (or (null? lst) (null? (cdr lst))) and return the argument or create the 3 segments using the first element as pivot and then append the recursion of the lesser and the higher and then appending the 3 lists together and you have them in order.
As inspiration here is a procedure that splits on odd? and not:
(define (split-odd lst)
(let loop ((lst lst) (odd '()) (even '()))
(cond
((null? lst) (list odd even))
((odd? (car lst)) (loop (cdr lst) (cons (car lst) odd) even))
(else (loop (cdr lst) odd (cons (car lst) even))))))
(split-odd '(1 2 3 4 5 6))
; ==> ((5 3 1) (6 4 2))
I am trying to learn Scheme, and I encounter a problem.
I am able to make a recursive function to create a list like (5,4,3,2,1). But I don't know how to create a function
(let's say (define (make_list n)) )
that has ascending order of elements likes (1,2,3,4,5....n).
Someone some hint?
(define (make_list n)
(if (= n 1)
(list 1)
(append (list n) (make_list (- n 1)))))
So this is how I make a list with n element, and it returns
> (make_list 3)
'(3 2 1)
> (make_list 5)
'(5 4 3 2 1)
What I need is to return something like:
> (make_list 3)
'(1 2 3)
> (make_list 5)
'(1 2 3 4 5)
You can make a list of ascending elements with the range function:
> (range 1 20)
'(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
If you want to iterate over this list consider using in-range instead, which will generate the list items as needed, e.g.:
> (in-range 1 20)
#<stream>
> (for ([i (in-range 1 20)])
(displayln (* i 10)))
10
20
30
...
However usually the likes of map, filter and fold are better ways to handle iteration.
Read the documentation here:
https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Flist..rkt%29._range%29%29
You should avoid using append where it is not necessary.
Append adds elements to the back of your list, for which it first needs to traverse the entire list to find the end. Cons does not need to do this, it can just add elements to the front immediately.
Both an ascending list and a descending one can be created using just cons.
(define (desc-list n)
(if (= n 1)
(list 1)
(cons n (desc-list (- n 1)))))
> (desc-list 5)
'(5 4 3 2 1)
(define (asc-list from to)
(if (> from to)
'()
(cons from (asc-list (+ from 1) to))))
> (asc-list 1 5)
'(1 2 3 4 5)
Though you could use append if you really want too.
All you have to do to get what you want then is reverse the parameters you pass to append.
(define (make_list n)
(if (= n 1)
(list 1)
(append (make_list (- n 1)) (list n))))
> (make_list 5)
'(1 2 3 4 5)
So you were very close.
Based on your current definition you have
(make-list 5) = (append (list 5) (make-list 4))
= { 5 } + { 4 ..... 1 }
but you want
(make-list 5) = { 1 ..... 4 } + { 5 }
= (append ... ...)
so to change the order of the result you just need to change the order in which you are creating the result.
Don't make a list one element a time with append. append appends two lists linear time so if you do that for each element in an argument you might make it quadratic time.
Lists are cons-ed from end to beginning. If you want to make a list 0..n you need to count downwards from n while you are accumulating, like this:
(define (make-list n)
(define (helper n acc)
(if (< n 0)
acc
(helper (- n 1) (cons n acc))))
(helper n '()))
Sometimes you cannot do that and then you usually would first make the list in reverse, then reverse it. that is two linear time operations making the end result linear too:
(define (sum lst1 lst2)
(let helper ((lst1 lst1) (lst2 lst2) (acc '()))
(if (null? lst1)
(reverse acc)
(helper (cdr lst1)
(cdr lst2)
(cons (+ (car lst1) (car lst2)) acc)))))
Just adding to this thread that srfi-1 contains the iota function
; (iota numElems [start] [step])
> (iota 10)
(0 1 2 3 4 5 6 7 8 9)
> (iota 10 0 2)
(0 2 4 6 8 10 12 14 16 18)
> (iota 10 10 1)
(10 11 12 13 14 15 16 17 18 19)
Think about using a sub-procedure. You could use your code as the sub-procedure and just reverse the result in the main procedure:
(define (make-list n)
(define (sub n)
(if (= n 1)
(list 1)
(append (list n) (sub (- n 1)))))
(reverse (sub n)))
Alternatively, and more efficiently, you can use an accumulator (called res in this example); it uses cons rather than append, and doesn't need an extra reverse step:
(define (make-list n)
(define (sub n res)
(if (< n 1)
res
(sub (- n 1) (cons n res))))
(sub n null))
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).