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-14

.1.5

| 13:50 | .1.5 - わだばLisperになる を含むブックマーク はてなブックマーク - .1.5 - わだばLisperになる

前回のmy-setqの定義ですが、Common Lispだと、setを使うとスペシャル変数に代入してしまうことを寝る前に思い出しました。

(defmacro my-setq (&rest symbols-and-values)
  (do ((l symbols-and-values (cddr l))
       (val () (set (car l) `,(cadr l))))      
      ((endp l) val)))

これだとローカル変数には代入せず、スペシャル変数にだけ代入するという謎なものができます。

(let (x y)
  (my-setq x 10 y 30)
  (values x y
  (symbol-value 'x)
  (symbol-value 'y)))
=> nil, nil, 10, 30

結局Common Lispだと、

(defmacro my-setq (&rest symbols-and-values)
  (do ((l symbols-and-values (cddr l))
       (form () (cons `(setq ,(car l) ,(cadr l)) form)))      
      ((endp l) `(progn ,@(nreverse form)))))

のようになるのかもしれません。

CADRのLisp Machine Lispでは、setはsetqのqが取れただけの動きのようなので、以上Common LispとLisp MachineLispの違いというところなのかなーという、全く役に立たない考察でした。

.1

| 13:50 | .1 - わだばLisperになる を含むブックマーク はてなブックマーク - .1 - わだばLisperになる

何となくネタ切れという感じで、更新が途絶えがちになってしまうのですが、あまり考えないで、日々Lispを触ってみているプログラム経験初心者の感想を書き散らかすということに方針を変えてみようかと思います。

適当にごちゃごちゃとLispのコードを書き散らかしてはいるのですが、あまり自分以外のコードを読んだりすることはなかったりするので、先達のコードを読んで研究してみようと思い立ちました。

ぼーっと眺めるだけだとあまり効果がなさそうなので、

1) お題を一定時間じっくり観察する。

2) その後、一切見ないで、再現する。

3) 確認と感想をまとめる。

のサイクルを繰り返してみることを試すことにしました。

写経ってやつでしょうか。

ということで、今回のお題は、LispマシンCADRのsetqの定義です。

1977~80年位のコードで、ファイル名は、qfctns.lispです。

先達すぎると思いますが、レトロコンピューティングが自分の趣味なので…。

Lispの方言はLisp machine lispです。

お題:

(DEFUN SETQ (&QUOTE &REST SYMBOLS-AND-VALUES)
  (PROG (VAL)
   L	(COND ((NULL SYMBOLS-AND-VALUES) (RETURN VAL)))
	(SET (CAR SYMBOLS-AND-VALUES) (SETQ VAL (EVAL (CADR SYMBOLS-AND-VALUES))))
	(SETQ SYMBOLS-AND-VALUES (CDDR SYMBOLS-AND-VALUES))
	(GO L)))

初見時の感想:

  • "Eってなんだ?
  • setが使われているのを初めて見た。
  • なんでevalが使われているんだ。

再現:

(defun my-setq (&rest symbols-and-vars)
  (prog (l var)
        (setq l symbols-and-vars)
    l   (cond ((null l) (return var)))
	(set (car l) (setq var (eval (cadr l))))
	(setq l (cddr l))
	(go l)))

とりあえず、"eは無視して記憶を辿って再現し、実行。

(my-setq foo 10 bar 20)

=> The variable FOO is unbound.

あ、そうか、そうだよね。"eは、引数をクオートするってことか。

ということで、"eを実現する方法を色々考えてみたけれど分からないので、defmacroを使うことにした。

しかし、defunがdefmacroに変っただけ。

(defmacro my-setq (&rest symbols-and-vars)
  (prog (l var)
        (setq l symbols-and-vars)
    l   (cond ((null l) (return var)))
	(set (car l) (setq var (eval (cadr l))))
	(setq l (cddr l))
	(go l)))

これで動作した。

確認と感想:

  • &restを直接いじっているけど良いのだろうか。
  • ラムダリストキーワードの"eと内部でのevalの組み合わせはdefmacroに統合されたのかもしれない。
  • 関数とマクロの中間みたいな微妙なマクロもあるのかもしれない。

もう少し今風に書き直してみた。

(defmacro my-setq (&rest symbols-and-values)
  (do ((l symbols-and-values (cddr l))
       (val () (set (car l) `,(cadr l))))      
      ((endp l) val)))