Multiple bindings in a for loop - 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).

Related

Combinations with pairs

I am trying to combine a list of pairs in scheme to get all possible combinations. For example:
((1 2) (3 4) (5 6)) --> ((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
I've been able to solve it (I think) using a "take the first and prepend it to the cdr of the procedure" with the following:
(define (combine-pair-with-list-of-pairs P Lp)
(apply append
(map (lambda (num)
(map (lambda (pair)
(cons num pair)) Lp)) P)))
(define (comb-N Lp)
(if (null? Lp)
'(())
(combine-pair-with-list-of-pairs (car Lp) (comb-N (cdr Lp)))))
(comb-N '((1 2)(3 4)(5 6)))
; ((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
However, I've been having trouble figuring out how I can use a procedure that only takes two and having a wrapper around it to be able to define comb-N by calling that function. Here it is:
(define (combinations L1 L2)
(apply append
(map (lambda (L1_item)
(map (lambda (L2_item)
(list L1_item L2_item))
L2))
L1)))
(combinations '(1) '(1 2 3))
; ((1 1) (1 2) (1 3))
I suppose the difficulty with calling this function is it expects two lists, and the recursive call is expecting a list of lists as the second argument. How could I call this combinations function to define comb-N?
difficulty? recursion? where?
You can write combinations using delimited continuations. Here we represent an ambiguous computation by writing amb. The expression bounded by reset will run once for each argument supplied to amb -
(define (amb . lst)
(shift k (append-map k lst)))
(reset
(list (list (amb 'a 'b) (amb 1 2 3))))
((a 1) (a 2) (a 3) (b 1) (b 2) (b 3))
how it works
The expression is evaluated through the first amb where the continuation is captured to k -
k := (list (list ... (amb 1 2 3)))
Where applying k will supply its argument to the "hole" left by amb's call to shift, represented by ... above. We can effectively think of k in terms of a lambda -
k := (lambda (x) (list (list x (amb 1 2 3)))
amb returns an append-map expression -
(append-map k '(a b))
Where append-map will apply k to each element of the input list, '(a b), and append the results. This effectively translates to -
(append
(k 'a)
(k 'b))
Next expand the continuation, k, in place -
(append
(list (list 'a (amb 1 2 3))) ; <-
(list (list 'b (amb 1 2 3)))) ; <-
Continuing with the evaluation, we evaluate the next amb. The pattern is continued. amb's call to shift captures the current continuation to k, but this time the continuation has evolved a bit -
k := (list (list 'a ...))
Again, we can think of k in terms of lambda -
k := (lambda (x) (list (list 'a x)))
And amb returns an append-map expression -
(append
(append-map k '(1 2 3)) ; <-
(list (list 'b ...)))
We can continue working like this to resolve the entire computation. append-map applies k to each element of the input and appends the results, effectively translating to -
(append
(append (k 1) (k 2) (k 3)) ; <-
(list (list 'b ...)))
Expand the k in place -
(append
(append
(list (list 'a 1)) ; <-
(list (list 'a 2)) ; <-
(list (list 'a 3))) ; <-
(list (list 'b (amb 1 2 3))))
We can really start to see where this is going now. We can simplify the above expression to -
(append
'((a 1) (a 2) (a 3)) ; <-
(list (list 'b (amb 1 2 3))))
Evaluation now continues to the final amb expression. We will follow the pattern one more time. Here amb's call to shift captures the current continuation as k -
k := (list (list 'b ...))
In lambda terms, we think of k as -
k := (lambda (x) (list (list 'b x)))
amb returns an append-map expression -
(append
'((a 1) (a 2) (a 3))
(append-map k '(1 2 3))) ; <-
append-map applies k to each element and appends the results. This translates to -
(append
'((a 1) (a 2) (a 3))
(append (k 1) (k 2) (k 3))) ; <-
Expand k in place -
(append
'((a 1) (a 2) (a 3))
(append
(list (list 'b 1)) ; <-
(list (list 'b 2)) ; <-
(list (list 'b 3)))) ; <-
This simplifies to -
(append
'((a 1) (a 2) (a 3))
'((b 1) (b 2) (b 3))) ; <-
And finally we can compute the outermost append, producing the output -
((a 1) (a 2) (a 3) (b 1) (b 2) (b 3))
generalizing a procedure
Above we used fixed inputs, '(a b) and '(1 2 3). We could make a generic combinations procedure which applies amb to its input arguments -
(define (combinations a b)
(reset
(list (list (apply amb a) (apply amb b)))))
(combinations '(a b) '(1 2 3))
((a 1) (a 2) (a 3) (b 1) (b 2) (b 3))
Now we can easily expand this idea to accept any number of input lists. We write a variadic combinations procedure by taking a list of lists and map over it, applying amb to each -
(define (combinations . lsts)
(reset
(list (map (lambda (each) (apply amb each)) lsts))))
(combinations '(1 2) '(3 4) '(5 6))
((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
Any number of lists of any length can be used -
(combinations
'(common rare)
'(air ground)
'(electric ice bug)
'(monster))
((common air electric monster)
(common air ice monster)
(common air bug monster)
(common ground electric monster)
(common ground ice monster)
(common ground bug monster)
(rare air electric monster)
(rare air ice monster)
(rare air bug monster)
(rare ground electric monster)
(rare ground ice monster)
(rare ground bug monster))
related reading
In Scheme, we can use Olivier Danvy's original implementation of shift/reset. In Racket, they are supplied via racket/control
(define-syntax reset
(syntax-rules ()
((_ ?e) (reset-thunk (lambda () ?e)))))
(define-syntax shift
(syntax-rules ()
((_ ?k ?e) (call/ct (lambda (?k) ?e)))))
(define *meta-continuation*
(lambda (v)
(error "You forgot the top-level reset...")))
(define abort
(lambda (v)
(*meta-continuation* v)))
(define reset-thunk
(lambda (t)
(let ((mc *meta-continuation*))
(call-with-current-continuation
(lambda (k)
(begin
(set! *meta-continuation* (lambda (v)
(begin
(set! *meta-continuation* mc)
(k v))))
(abort (t))))))))
(define call/ct
(lambda (f)
(call-with-current-continuation
(lambda (k)
(abort (f (lambda (v)
(reset (k v)))))))))
For more insight on the use of append-map and amb, see this answer to your another one of your questions.
See also the Compoasable Continuations Tutorial on the Scheme Wiki.
remarks
I really struggled with functional style at first. I cut my teeth on imperative style and it took me some time to see recursion as the "natural" way of thinking to solve problems in a functional way. However I offer this post in hopes to provoke you to reach for even higher orders of thinking and reasoning. Recursion is the topic I write about most on this site but I'm here saying that sometimes even more creative, imaginative, declarative ways exist to express your programs.
First-class continuations can turn your program inside-out, allowing you to write a program which manipulates, consumes, and multiplies itself. It's a sophisticated level of control that's part of the Scheme spec but only fully supported in a few other languages. Like recursion, continuations are a tough nut to crack, but once you "see", you wish you would've learned them earlier.
As suggested in the comments you can use recursion, specifically, right fold:
(define (flatmap foo xs)
(apply append
(map foo xs)))
(define (flatmapOn xs foo)
(flatmap foo xs))
(define (mapOn xs foo)
(map foo xs))
(define (combs L1 L2) ; your "combinations", shorter name
(flatmapOn L1 (lambda (L1_item)
(mapOn L2 (lambda (L2_item) ; changed this:
(cons L1_item L2_item)))))) ; cons NB!
(display
(combs '(1 2)
(combs '(3 4)
(combs '(5 6) '( () )))))
; returns:
; ((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
So you see, the list that you used there wasn't quite right, I changed it back to cons (and thus it becomes fully the same as combine-pair-with-list-of-pairs). That way it becomes extensible: (list 3 (list 2 1)) isn't nice but (cons 3 (cons 2 (cons 1 '()))) is nicer.
With list it can't be used as you wished: such function receives lists of elements, and produces lists of lists of elements. This kind of output can't be used as the expected kind of input in another invocation of that function -- it would produce different kind of results. To build many by combining only two each time, that combination must produce the same kind of output as the two inputs. It's like +, with numbers. So either stay with the cons, or change the combination function completely.
As to my remark about right fold: that's the structure of the nested calls to combs in my example above. It can be used to define this function as
(define (sequence lists)
(foldr
(lambda (list r) ; r is the recursive result
(combs list r))
'(()) ; using `()` as the base
lists))
Yes, the proper name of this function is sequence (well, it's the one used in Haskell).

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))

How to find partitions of a list in Scheme

Say there is any given list in Scheme. This list is ‘(2 3 4)
I want to find all possible partitions of this list. This means a partition where a list is separated into two subsets such that every element of the list must be in one or the other subsets but not both, and no element can be left out of a split.
So, given the list ‘(2 3 4), I want to find all such possible partitions. These partitions would be the following: {2, 3} and {4}, {2, 4} and {3}, and the final possible partition being {3, 4} and {2}.
I want to be able to recursively find all partitions given a list in Scheme, but I have no ideas on how to do so. Code or psuedocode will help me if anyone can provide it for me!
I do believe I will have to use lambda for my recursive function.
I discuss several different types of partitions at my blog, though not this specific one. As an example, consider that an integer partition is the set of all sets of positive integers that sum to the given integer. For instance, the partitions of 4 is the set of sets ((1 1 1 1) (1 1 2) (1 3) (2 2) (4)).
The process is building the partitions is recursive. There is a single partition of 0, the empty set (). There is a single partition of 1, the set (1). There are two partitions of 2, the sets (1 1) and (2). There are three partitions of 3, the sets (1 1 1), (1 2) and (3). There are five partitions of 4, the sets (1 1 1 1), (1 1 2), (1 3), (2 2), and (4). There are seven partitions of 5, the sets (1 1 1 1 1), (1 1 1 2), (1 2 2), (1 1 3), (1 4), (2 3) and (5). And so on. In each case, the next-larger set of partitions is determined by adding each integer x less than or equal to the desired integer n to all the sets formed by the partition of n − x, eliminating any duplicates. Here's how I implement that:
Petite Chez Scheme Version 8.4
Copyright (c) 1985-2011 Cadence Research Systems
> (define (set-cons x xs)
(if (member x xs) xs
(cons x xs)))
> (define (parts n)
(if (zero? n) (list (list))
(let x-loop ((x 1) (xs (list)))
(if (= x n) (cons (list n) xs)
(let y-loop ((yss (parts (- n x))) (xs xs))
(if (null? yss) (x-loop (+ x 1) xs)
(y-loop (cdr yss)
(set-cons (sort < (cons x (car yss)))
xs))))))))
> (parts 6)
((6) (3 3) (2 2 2) (2 4) (1 1 4) (1 1 2 2) (1 1 1 1 2)
(1 1 1 1 1 1) (1 1 1 3) (1 2 3) (1 5))
I'm not going to solve your homework for you, but your solution will be similar to the one given above. You need to state your algorithm in recursive fashion, then write code to implement that algorithm. Your recursion is going to be something like this: For each item in the set, add the item to each partition of the remaining items of the set, eliminating duplicates.
That will get you started. If you have specific questions, come back here for additional help.
EDIT: Here is my solution. I'll let you figure out how it works.
(define range (case-lambda ; start, start+step, ..., start+step<stop
((stop) (range 0 stop (if (negative? stop) -1 1)))
((start stop) (range start stop (if (< start stop) 1 -1)))
((start stop step) (let ((le? (if (negative? step) >= <=)))
(let loop ((x start) (xs (list)))
(if (le? stop x) (reverse xs) (loop (+ x step) (cons x xs))))))
(else (error 'range "unrecognized arguments"))))
(define (sum xs) (apply + xs)) ; sum of elements of xs
(define digits (case-lambda ; list of base-b digits of n
((n) (digits n 10))
((n b) (do ((n n (quotient n b))
(ds (list) (cons (modulo n b) ds)))
((zero? n) ds)))))
(define (part k xs) ; k'th lexicographical left-partition of xs
(let loop ((ds (reverse (digits k 2))) (xs xs) (ys (list)))
(if (null? ds) (reverse ys)
(if (zero? (car ds))
(loop (cdr ds) (cdr xs) ys)
(loop (cdr ds) (cdr xs) (cons (car xs) ys))))))
(define (max-lcm xs) ; max lcm of part-sums of 2-partitions of xs
(let ((len (length xs)) (tot (sum xs)))
(apply max (map (lambda (s) (lcm s (- tot s)))
(map sum (map (lambda (k) (part k xs))
(range (expt 2 (- len 1)))))))))
(display (max-lcm '(2 3 4))) (newline) ; 20
(display (max-lcm '(2 3 4 6))) (newline) ; 56
You can find all 2-partitions of a list using the built-in combinations procedure. The idea is, for every element of a (len-k)-combination, there will be an element in the k-combination that complements it, producing a pair of lists whose union is the original list and intersection is the empty list.
For example:
(define (2-partitions lst)
(define (combine left right)
(map (lambda (x y) (list x y)) left right))
(let loop ((m (sub1 (length lst)))
(n 1))
(cond
((< m n) '())
((= m n)
(let* ((l (combinations lst m))
(half (/ (length l) 2)))
(combine (take l half)
(reverse (drop l half)))))
(else
(append
(combine (combinations lst m)
(reverse (combinations lst n)))
(loop (sub1 m) (add1 n)))))))
then you can build the partitions as:
(2-partitions '(2 3 4))
=> '(((2 3) (4))
((2 4) (3))
((3 4) (2)))
(2-partitions '(4 6 7 9))
=> '(((4 6 7) (9))
((4 6 9) (7))
((4 7 9) (6))
((6 7 9) (4))
((4 6) (7 9))
((4 7) (6 9))
((6 7) (4 9)))
Furthermore, you can find the max lcm of the partitions:
(define (max-lcm lst)
(define (local-lcm arg)
(lcm (apply + (car arg))
(apply + (cadr arg))))
(apply max (map local-lcm (2-partitions lst))))
For example:
(max-lcm '(2 3 4))
=> 20
(max-lcm '(4 6 7 9))
=> 165
To partition a list is straightforward recursive non-deterministic programming.
Given an element, we put it either into one bag, or the other.
The very first element will go into the first bag, without loss of generality.
The very last element must go into an empty bag only, if such is present at that time. Since we start by putting the first element into the first bag, it can only be the second:
(define (two-parts xs)
(if (or (null? xs) (null? (cdr xs)))
(list xs '())
(let go ((acc (list (list (car xs)) '())) ; the two bags
(xs (cdr xs)) ; the rest of list
(i (- (length xs) 1)) ; and its length
(z '()))
(if (= i 1) ; the last element in the list is reached:
(if (null? (cadr acc)) ; the 2nd bag is empty:
(cons (list (car acc) (list (car xs))) ; add only to the empty 2nd
z) ; otherwise,
(cons (list (cons (car xs) (car acc)) (cadr acc)) ; two solutions,
(cons (list (car acc) (cons (car xs) (cadr acc))) ; adding to
z))) ; either of the two bags;
(go (list (cons (car xs) (car acc)) (cadr acc)) ; all solutions after
(cdr xs) ; adding to the 1st bag
(- i 1) ; and then,
(go (list (car acc) (cons (car xs) (cadr acc))) ; all solutions
(cdr xs) ; after adding
(- i 1) ; to the 2nd instead
z))))))
And that's that!
In writing this I was helped by following this earlier related answer of mine.
Testing:
(two-parts (list 1 2 3))
; => '(((2 1) (3)) ((3 1) (2)) ((1) (3 2)))
(two-parts (list 1 2 3 4))
; => '(((3 2 1) (4))
; ((4 2 1) (3))
; ((2 1) (4 3))
; ((4 3 1) (2))
; ((3 1) (4 2))
; ((4 1) (3 2))
; ((1) (4 3 2)))
It is possible to reverse the parts before returning, or course; I wanted to keep the code short and clean, without the extraneous details.
edit: The code makes use of a technique by Richard Bird, of replacing (append (g A) (g B)) with (g' A (g' B z)) where (append (g A) y) = (g' A y) and the initial value for z is an empty list.
Another possibility is for the nested call to go to be put behind lambda (as the OP indeed suspected) and activated when the outer call to go finishes its job, making the whole function tail recursive, essentially in CPS style.

Optional keyword argument and multiple arguments exercise

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))))

Resources