Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2007-09-26

.6

| 18:35 | .6 - わだばLisperになる を含むブックマーク はてなブックマーク - .6 - わだばLisperになる

今回は、またMaclispのファイルで、UMLMAC.LSPというファイルのdolistを観察/再現してみました。

1981年より前のファイルのようです。

お題:

(defmacro DOLIST ((var form index) &rest body &aux dummy decls)
   (setq decls (cond ((and body 
			   (not (atom (car body)))
			   (eq (caar body) 'DECLARE))
		      (prog2 () (cdar body) (pop body)))))
   (cond (index (push `(FIXNUM ,INDEX) decls)
		(setq index (ncons `(,INDEX 0 (1+ ,INDEX)) ))))
   (and decls (setq decls  (ncons `(DECLARE ,.decls))))
   (si:gen-local-var dummy)
   `(DO ((,DUMMY ,FORM (CDR ,DUMMY)) (,VAR) ,.index )
	((NULL ,DUMMY))
      ,@decls
      (SETQ ,VAR (CAR ,DUMMY))  ,.BODY))

再現:

(defmacro my-old-dolist ((var list &optional index) &body body &aux decls dummy) ;indexの扱いが良く分からない。
  (setq decls (cond ((and (consp (car body)) ;ちょっと違うけど同じことだと思う。
			  (eq (caar body) 'declare)
			  (prog2 () (cdar body) (pop body))))))
  (cond (index (push `(fixnum ,index) decls)
	       (setq index `((,index 0 (1+ ,index)))))) ;`(())と二重にするんじゃなくてncons使ってました。
  (push 'declare decls)			;indexがnilの場合の対策漏れ。(declare)というものが出来てしまう。-> (and decls (push 'declare decls))
  (setq dummy (gensym))
  `(do ((,dummy ,list (cdr ,dummy))
	(,var)				;抜けてました。
	,@index)			;,.使ってました。
       ((null ,dummy))
     ,decls
     (setq ,var (car ,dummy))
     ,@body))				;,.使ってました。

間違ったところ:

  1. varをdo内部で宣言するのを抜かしてしまった。
  2. declareされなかった場合の処理を抜かしてしまった。

考察:

  • 現行のCommon Lispのdolistでは、変数束縛のところの3つ目は、結果を返すところになってますが、これは、インデックスの変数を指定する場所になってます。
(my-dolist (i '(foo bar baz) idx)
  (format t "~A: ~A~%" idx i))
=> 
0: FOO
1: BAR
2: BAZ

これはこれで使えそうな気がします。

  • 返り値は、nil
  • (prog2 () 返したい処理 ~)
    • これはこの当時のイディオムの様で、今ならprog1を使うところだと思います。prog1より先にprog2が存在していた理由は謎です。
  • si:gen-local-var
    • これは、gentemp+適用した変数をローカル扱い?にするもののようですが詳細は謎です。gensymに置き換えて再現で良いんだとは思います。
  • ncons
(defun ncons (x)
  (cons x () ))

のような関数のようです。`( (foo))とは書かずに、(ncons `(foo))と書いています。

  • &optionalでなくても引数を省略できている様子

Tops-20のMaclispで動作を確認しましたが、index引数は省略できてました。詳細は謎です。

  • ,.(コンマドット)
    • Maclispでも、Common Lispのように,.と,@の違いは、nconcを使うか、appendを使うかの違いなのか不明ですが、使い分けしてるようなので、多分、Common Lispと同じのようです。

その他

  • マクロの展開される本体の部分は、大文字で書く」派
  • 「関数/マクロ名は大文字にする」派