lambdaの形とletの形 — #:g1

Posted 2011-02-28 09:35:00 GMT

letはlambdaを変形すれば作ることができるというのはよく知られているかと思います。
ふとmap系の関数もlambda系な配置なので、これをlet系に変形したらどうかなと思い、

(defmacro mlet ((&rest binding) &body body)
  `(mapcar (lambda (,@(mapcar #'car binding))
             ,@body)
           ,@(mapcar #'cadr binding)))
のようなものを書いてみました。
(mlet ((x '(1 2 3 4 5))
       (y '(a b c d e)))
  (list x y))
;=> ((1 A) (2 B) (3 C) (4 D) (5 E))
dolistの複数回せるdolistsというマクロを良くみますが、それがリストの返り値を返すものというところでしょうか。

これは絶対他の人も考えてるだろうなと思ったのでmletとかlmapとかmaplet等色々な組み合わせで検索してみたところ、そのものずばりなErann Gatさん作のmapletをみつけました。
(defmacro maplet (bindings &body body)
  `(mapcar (fn ,(mapcar #'car bindings) ,@body)
           ,@(mapcar #'second bindings)))
(maplet ((x '(1 2 3 4 5))
         (y '(a b c d e)))
  (list x y))
;=> ((1 A) (2 B) (3 C) (4 D) (5 E))
mapletという名前の方が良いですね。

mapcarとmapletの違いですが、mapletは構文にする必要があるのでマクロになるため、APPLYに渡す、ということができなくなったりします。また、無名関数以外を渡すときに逆に引数を書いてやらないといけない手間が増えたりしますが、無名関数を書くのが面倒ということの方が多い気がするのでmapletも結構便利かもしれないと思いました。

ちなみに、似たようなところでは、TAOのimageがあり
(image i '(1 2 3 4) (* 2 i))
;=> (2 4 6 8)
という風に括弧が少ない版のmapletという感じです。dolistの括弧が少ない版とも考えられるかもしれません(ボディ部は1つの式しか取れないようです。)
また、これを拡張した、imagenというのがあり、mapletの括弧が少ない版という感じです。
(imagen (i '(1 2 3 4))
        (j '(a b c d))
        (list i j))
;=> ((1 A) (2 B) (3 C) (4 D))
lambda <=> let で色々変形を試してみると思わぬ発見があるやもしれません。

comments powered by Disqus