Domanda

As you can see in the example below, map function in Scheme is variadic function.

> (map (lambda (number1 number2)
     (+ number1 number2))
   '(1 2 3 4)
   '(10 100 1000 10000))
'(11 102 1003 10004)

I want to implement this variadic option, but I only succeeded to find the two arguments map implementation:

(define (map f lst)
   (if (null? lst)
       '()
       (cons (f (car lst)) (map f (cdr lst)))))

Can someone help me implement variadic map function?

È stato utile?

Soluzione

In Scheme, you can write a variadic function as (lambda x ...), in which case x gets bound to the entire list of arguments, or by using an improper lambda list, e.g., (lambda (a b c . ds) ...), which takes at least three arguments, and binds ds to the list of the remaining arguments. The code you're trying to write, then, would be something like (I'm writing in R5RS Scheme):

(define (my-map function list1 . more-lists)
  (define (some? function list)
    ;; returns #f if (function x) returns #t for 
    ;; some x in the list
    (and (pair? list)
         (or (function (car list))
             (some? function (cdr list)))))
  (define (map1 function list)
    ;; non-variadic map.  Returns a list whose elements are
    ;; the result of calling function with corresponding
    ;; elements of list
    (if (null? list)
        '()
        (cons (function (car list))
              (map1 function (cdr list)))))
  ;; Variadic map implementation terminates
  ;; when any of the argument lists is empty
  (let ((lists (cons list1 more-lists)))
    (if (some? null? lists)
        '()
        (cons (apply function (map1 car lists))
              (apply my-map function (map1 cdr lists))))))

This works as expected:

(my-map + '(0 2 5) '(1 2 3))
;=> (1 4 8)

Notice that to make this work, we needed a non-variadic map (here called map1) in order to do (map1 car lists) to get the argument list to call function with, and (map1 cdr lists) to get the rests of the lists to recurse with. To write a variadic map (here called my-map), you already need an implementation of the non-variadic map.

Altri suggerimenti

You've got your answer but note that there is a syntactic keyword case-lambda that lets you be explicit about the procedure to use when the number or arguments varies. You'd use it like this:

(define my-map
  (case-lambda
   ((func list) …)
   ((func list1 list2) …)
   (…)
   ((func . lists) …)))

This way, you can optimize your handling of different argument counts. The case-lambda generates a 'wrapping lambda' that essentially looks like this (but might be compiled more efficiently):

(define my-map
  (lambda args ;; illustration only, implementations vary.
    (apply (let ((len (length args)))
             (cond ((= 2 len) (lambda (func list) …))
                   …))
           args)))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top