1
votes

In lisp/scheme, is there any form using set product as function input? map form uses n length-equal lists for a function which needs n arguments. Sometimes, we need the arguments to come from the product of a group of sets. For example:

(pmap (λ (d p) foo)
           A B)

Here, list A may have different length with B, and pmap feeds each element of the product of A and B to the lambda expression.

Form for* of scheme/racket can do this job:

(for* ([x '(0 2 4)]
       [y '(1 3 5)])
      ((λ (d p)
           (printf "(~a, ~a)\n" d p))
       x y))

Output:

(0, 1)
(0, 3)
(0, 5)
(2, 1)
(2, 3)
(2, 5)
(4, 1)
(4, 3)
(4, 5)

I want to know whether there exists other means similar to map or fold to do this in scheme.

2

2 Answers

1
votes

As far as I know such a thing is not present in the standard. It is however not a problem to write one.

For an overview over useful list functions, I can recommend srfi1, which gives you quite a few useful operations besides map and fold.

http://srfi.schemers.org/srfi-1/srfi-1.html

0
votes

I wrote the following implementation of pmap. It works using only cons, car, cdr, null?, apply, map and reverse and supports any number of arguments like map does.

(define (pmap f . xs) 
  (define (carry a xs ys then)
    (if (and (not (null? ys)) (null? (car ys)))
        '()
        (if (null? xs) 
            (then (reverse a))
            (if (null? (car xs))
                (if (null? (cdr xs)) 
                    '()
                    (carry (cons (car ys) a) (cons (cdr (car (cdr xs))) (cdr (cdr xs))) (cdr ys) then))
                (carry (cons (car xs) a) (cdr xs) (cdr ys) then)))))

  (define (pmap-helper f xs ys)
    (carry '() xs ys 
           (lambda (xs)
             (cons (apply f (map car xs)) 
                   (pmap-helper f (cons (cdr (car xs)) (cdr xs)) ys)))))

  (pmap-helper f xs xs))

(display (pmap list '(0 2 4) '(1 3 5))) (newline)
;((0 1) (2 1) (4 1) (0 3) (2 3) (4 3) (0 5) (2 5) (4 5))

The only difference is that the earlier lists are iterated over faster than later ones where as your example is the reverse. This pmap can be modified to do that:

(define (pmap f . xs) 
  (define (carry a xs ys then)
    (if (and (not (null? ys)) (null? (car ys)))
        '()
        (if (null? xs) 
            (then (reverse a))
            (if (null? (car xs))
                (if (null? (cdr xs)) 
                    '()
                    (carry (cons (car ys) a) (cons (cdr (car (cdr xs))) (cdr (cdr xs))) (cdr ys) then))
                (carry (cons (car xs) a) (cdr xs) (cdr ys) then)))))

  (define (pmap-helper f xs ys)
    (carry '() xs ys 
           (lambda (xs)
             (cons (apply f (reverse (map car xs))) 
                   (pmap-helper f (cons (cdr (car xs)) (cdr xs)) ys)))))

  (let ((xs (reverse xs)))
    (pmap-helper f xs xs)))

(display (pmap list '(0 2 4) '(1 3 5))) (newline)
; ((0 1) (0 3) (0 5) (2 1) (2 3) (2 5) (4 1) (4 3) (4 5))