10分でコーディング x 2 〜リストの破壊的操作篇に挑戦
10分でコーディング x 2 〜リストの破壊的操作篇〜 - わだばLisperになる - cadrグループ をやってみた。
まずは完成したコード
(defun nalist-to-plist (alist)
(loop for x on alist by #'cddr
do (rotatef (caar x) (cdar x) (cdr x) (car x)))
alist)
(defun nplist-to-alist (plist)
(loop for x on plist
do (rotatef (cddr x) (cadr x) (car x) (cdr x)))
plist)
nalist-to-plist の方は40分くらいかかってしまった。破壊的操作は難しい。。。 nplist-to-alist の方は4分ほど。
で気づいたのが rotatef の挙動が微妙。
(rotatef (caar x) (cdar x) (cdr x) (car x))
を
(rotatef (cdr x) (car x) (caar x) (cdar x))
と書くと動かない。 SBCL、CCL、CLISP、ABCL ともに動かない。だけど ACL では動いた。
SBCL で (rotatef (cdr x) (car x) (caar x) (cdar x)) をマクロ展開したのが次のコード
(LET* ((#:TMP892 X) (#:TMP894 X) (#:G895 X) (#:G897 X))
(MULTIPLE-VALUE-BIND
(#:NEW891)
(CAR #:TMP894)
(MULTIPLE-VALUE-BIND
(#:NEW893)
(CAAR #:G895)
(MULTIPLE-VALUE-BIND
(#:G896)
(CDAR #:G897)
(MULTIPLE-VALUE-BIND
(#:G898)
(CDR #:TMP892)
(SB-KERNEL:%RPLACD #:TMP892 #:NEW891)
(SB-KERNEL:%RPLACA #:TMP894 #:NEW893)
(SB-KERNEL:%RPLACA (CAR #:G895) #:G896)
(SB-KERNEL:%RPLACD (CAR #:G897) #:G898)
NIL)))))
SB-KERNEL:%RPLACA の引数のところで car を使うのは駄目な気がする。
ACL で同じコードをマクロ展開したら次のコードになる。
(LET ((#:G5705 X))
(LET ((#:G5707 X))
(MULTIPLE-VALUE-BIND (#:G5704)
(CAR #:G5707)
(LET ((#:G5709 (CAR X)))
(MULTIPLE-VALUE-BIND (#:G5706)
(CAR #:G5709)
(LET ((#:G5711 (CAR X)))
(MULTIPLE-VALUE-BIND (#:G5708)
(CDR #:G5711)
(MULTIPLE-VALUE-BIND (#:G5710)
(CDR #:G5705)
(PROGN (EXCL::.INV-CDR #:G5705 #:G5704)
(EXCL::.INV-CAR #:G5707 #:G5706)
(EXCL::.INV-CAR #:G5709 #:G5708)
(EXCL::.INV-CDR #:G5711 #:G5710))
NIL))))))))
こっちは #:G5709 は事前に car されている。
バグかな。。。