さかもとのブログ

つらつらと

mapの実装

演習問題4.14が,mapに関する問題だった.

問題の内容は

Aさん,Bさんはそれぞれ超循環評価器の実験をしていた.Aさんは,mapの定義を入力し,それを使うテストプログラムをいくつか走らせたところ,うまく動いた.ところで,Bさんは,システムの組み込みのmapを基本手続きとして組み込んだ.Bさんのテストプログラムはうまく動かない.なぜか?

という感じ.
おそらく,<手続き>が属するクラス(評価器の場合はtag)がもともとの実装のものと,ここの評価器では違うから.
実際やってみると確かにうまく動かない.

ところで,mapの1引数のものはいつだかの演習で実装したのは覚えているけれど,複数の引数をとる場合は実装したっけ?と思い,mapを実装してみた.かなり微妙になった.

;1引数用
(define (map-for-one-argument proc arg)
  (if (null? arg)
      '()
      (cons (proc (car arg))
            (map-for-one-argument proc (cdr arg)))))

(define (my-map proc . args)
  (cond [(null? args) '()]
        [(= (length args) 1)
         (map-for-one-argument proc (car args))]
        [else
         (let ((cdr-args (map-for-one-argument cdr args)))
           (if (equal? cdr-args '(() ()))
               (set-cdr! cdr-args ()))
           (cons (apply proc (map-for-one-argument car args))
                 (apply my-map (cons proc cdr-args))))]))

なぜ

(let ((cdr-args (map-for-one-argument cdr args)))
   (if (equal? cdr-args '(() ()))
       (set-cdr! cdr-args ()))

を入れたかというと,再起呼び出し後,(null? args)で戻ってくると,

(cons (apply proc (map-for-one-argument car args))
      (apply my-map (cons proc cdr-args))))]))

の2つ目のapplyが

(apply my-map (proc () ()))

となり,applyができないので,

(apply my-map (proc ())

となるようにするため.
しかし,気持ちわるいな.なんとかならないのか.