(Scheme) Recursive function to compute all possibl

2019-02-15 19:29发布

问题:

What is an example of a recursive function to compute all possible combinations of lists? For example, (combine (list 1 2 3) (list 1 2)) should return '((1 1) (1 2) (2 1) (2 2) (3 1) (3 2)).

回答1:

Here's my solution. Requires SRFIs 1 and 26 to be available.

(define (cartesian-product first . rest)
  (define (iter l result)
    (define (prepend-all x)
      (map (cut cons <> x) l))
    (concatenate (map prepend-all result)))
  (map reverse (fold iter (map list first) rest)))


回答2:

Here's my take; I first define a helper concat/map, which takes a list and a function. Like regular map, it applies that function to each element in the list. Unlike map, though, it uses append to combine the results rather than cons. This is useful because we want to get back a single level of lists as an answer:

(define concat/map
  (lambda (ls f)
    (cond
      [(null? ls) '()]
      [else (append (f (car ls)) (concat/map (cdr ls) f))])))

Then, writing combine for two lists is straightforward. You take each element of the first list, then make every list combining it and an element x from the second list. Since this gives back a list of answers for each element in the first list, use concat/map to put it together as we want:

(define combine
  (lambda (xs ys)
    (concat/map xs (lambda (x)
                     (map (lambda (y) (list x y)) ys)))))

The version of combine that operates on one or more lists, let's call it combine*, is a bit trickier. Instead of making all the lists combining x with the elements from the second list, we just recursively ask for the product of all the remaining ys, and then cons x onto each of those results. The recursion stops when there's only two lists to combine, and uses the original combine in that case.

(define combine*
  (lambda (xs . ys*)
    (cond
      [(null? ys*) (map list xs)]
      [(null? (cdr ys*)) (combine xs (car ys*))]
      [else (concat/map xs (lambda (x)
                             (map (lambda (y) (cons x y))
                                  (apply combine* ys*))))])))

As a bonus, this pattern of using concat/map to do some work and combine the resulting answers is actually the list monad. It's simplified here, but the structure is in place.



标签: lisp scheme