*SERIES-IMPLICIT-MAP*の怪 — #:g1

Posted 2010-11-03 14:30:00 GMT

Seriesの先祖であるletS*では、

(defun pairwise-max (list1 list2)
  (Rlist (mapS #'max (Elist list1) (Elist list2))))
というのが、
(defun pairwise-max (list1 list2)
  (Rlist (max (Elist list1) (Elist list2))))
と書けたりします。Seriesで書くとすると、
(defun pairwise-max (list1 list2)
  (collect (#Mmax (scan list1) (scan list2))))
が、
(defun pairwise-max (list1 list2)
  (collect (max (scan list1) (scan list2))))
書けるということらしいのですが、ここで変っている点としては、SCANで生成したSeriesをSeriesを扱う関数でないMAXが受けているように見えること。
なかなか便利なような、思いっきり黒魔術のような感じなのですが、Seriesのソースの中の解説にこういうletSのような書き方ができるオプションについて解説がありました。
解説によると、
SERIES::*SERIES-IMPLICIT-MAP*
を非NILにすれば
(let* ((x (car (scan '((1) (2) (3)))))
       (y (1+ x))
       (z (collect-sum (* x y))))
  (print (list x y 4))
  (print z)
  (collect (list x (catenate #Z(a) (gensym)))))
のような書き方で、
(let* ((x (#Mcar (scan '((1) (2) (3)))))
       (y (#M1+ x))
       (z (collect-sum (#M* x y))))
  (collect-last (#Mprint (#Mlist x y (series 4))))
  (print z)
  (collect (#Mlist x (catenate #Z(a) (series (gensym))))))
と等価になるよ、とのこと。
#M等を使っていた方がなんとなくSeriesかそうでないかをソース上で意識できるので健全な気もしますが面白いです。
ちなみに上記の式は、マクロ展開すると、
(LET* ((#:OUT-35 (GENSYM)))
  (LET (#:ELEMENTS-31
        (#:LISTPTR-32 '(A))
        #:ELEMENTS-1
        (#:LISTPTR-2 '((1) (2) (3)))
        X
        Y
        #:OUT-13
        (Z 0)
        #:ITEMS-28
        (#:FLAG-29 NIL)
        #:OUT-37
        (#:LASTCONS-18 (LIST NIL))
        #:LST-19)
    (DECLARE (TYPE LIST #:LISTPTR-32)
             (TYPE LIST #:LISTPTR-2)
             (TYPE NUMBER Z)
             (TYPE BOOLEAN #:FLAG-29)
             (TYPE CONS #:LASTCONS-18)
             (TYPE LIST #:LST-19))
    (SETQ #:LST-19 #:LASTCONS-18)
    (TAGBODY
     #:LL-38
      (IF (ENDP #:LISTPTR-2)
          (GO SERIES::END))
      (SETQ #:ELEMENTS-1 (CAR #:LISTPTR-2))
      (SETQ #:LISTPTR-2 (CDR #:LISTPTR-2))
      (SETQ X (CAR #:ELEMENTS-1))
      (SETQ Y (1+ X))
      (SETQ #:OUT-13 (* X Y))
      (SETQ Z (+ Z #:OUT-13))
      (PRINT (LIST X Y 4))
      (IF #:FLAG-29
          (GO #:B-23))
      (IF (ENDP #:LISTPTR-32)
          (GO #:F-24))
      (SETQ #:ELEMENTS-31 (CAR #:LISTPTR-32))
      (SETQ #:LISTPTR-32 (CDR #:LISTPTR-32))
      (SETQ #:ITEMS-28 #:ELEMENTS-31)
      (GO #:D-21)
     #:F-24
      (SETQ #:FLAG-29 T)
     #:B-23
     NIL
      (SETQ #:ITEMS-28 #:OUT-35)
     #:D-21
      (SETQ #:OUT-37 (LIST X #:ITEMS-28))
      (SETQ #:LASTCONS-18 (SETF (CDR #:LASTCONS-18) (CONS #:OUT-37 NIL)))
      (GO #:LL-38)
     SERIES::END)
    (SETQ #:LST-19 (CDR #:LST-19))
    (PRINT Z)
    #:LST-19))
のようになってしまいます。
どうもSeriesで定義されているLETや関数などは組み合わさるとマクロ展開で別のものにごりごり変形するようですね…。

comments powered by Disqus