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


.8

| 04:53 | .8 - わだばLisperになる を含むブックマーク はてなブックマーク - .8 - わだばLisperになる

今日もSAILの昔のLispのアーカイブを探索してみていたところ怪しげなMaclispのコード群が結構ありました。

変ったletのフォーム、パターンマッチでマクロを定義するらしいmatch-macroというマクロ、その他色々…。

公開されているMITのMaclispのファイルでこんなに変ったものは目にしたことはなかったので、ちょっとびっくりしました。

今回は、その中の変ったletのフォームをマクロで再現して遊んでみました。

MATCH.118 (1981-05-27 00:41) (Maclisp)

http://www.saildart.org/prog/LSP/AID_LSP/.html/000130?129,5760

作者の詳細は不明ですが、このファイルが置かれているディレクトリにはrpgという署名が沢山あり、スタイルも統一されたものがあるのでrpg氏か、その一派だと思います。

それでrpg氏とは恐らく「デザインの「悪い方がよい」原則」で有名な、Richard Gabriel氏ではないかと思います。

  • 変った形式のlet

これのファイルを見て最初に思ったのは、LispUser.netさんのところで紹介されていた矢印付きletでした。

http://lispuser.net/memo/lisp/2007-01-28-01-54.html

殆どそのままなのですが、違いといえば、矢印が「<-」ではなく、そのまま矢印の文字を使っているところ(SAILではASCII以外の拡張文字が結構普通に使われていました)と、バインド部とボディ部を分けるキーワードが「do」だということと、「then」というキーワードが使えてthen以降は、先に定義した変数が使えます。このletを定義したソースが見付からないので何ともいえないのですが、thenが複数回使えるとすれば、letとlet*の組み合わせも一つの記述で実現できる方法だと思います。

  • 再現

基本的にリスト操作でごちゃごちゃ作りました。パッケージ名は適当です。

パッケージ名SRFIは、自分がSRFIを見て作った自分用のユーティリティ群です。srfi-breakだけ名前の衝突が面倒なのでを変えてます。

SRFI-1がそのままあれば良いのになーとかいつも思っているのですが、リスト操作系のCLのユーティリティ群で決定版ってのはあるんでしょうか。

(defpackage rpg
  (:use :cl)
  (:export let.))

(in-package :rpg)

(defmacro let. (&body form)
  (destructuring-bind (binds body)
      (separate 'do form :test #'eq)
    (let ((blist (separate 'then binds :test #'eq)))
      (reduce 
       (lambda (xx res)
	 `(let ,(do ((b xx (cdddr b))
		     res)
		    ((endp b) (nreverse res))
		    (let ((spec (srfi:take b 3)))
		      (or (eq (cadr spec) ')
			  (error "LET.: Bad bind."))
		      (push `(,(car spec) ,(caddr spec)) res)))
	    ,res))
       blist
       :initial-value `(progn ,@body)
       :from-end 'T) )))

;; 補助関数 (1 2 3 x 4 5 x 6 7 8) -> ((1 2 3)(4 5) (6 7 8))
(defun separate (item list &optional &key (test #'eql))
  (labels ((frob (item list acc)
	     (if (endp list)
		 (nreverse acc)
		 (multiple-value-bind (top rest)
		     (srfi:srfi-break (lambda (x) (funcall test item x)) list)
		   (frob item (cdr rest) (cons top acc))))))
    (frob item list () )))
(let. a ← 1 then
      b ← (+ a 2) then
      c ← 3 
      d ← 4 then
      e ← () do
      (list a b c d) 
      (reverse (list a b c d)))

が、

(LET ((A 1))
  (LET ((B (+ A 2)))
    (LET ((C 3) (D 4))
      (LET ((E NIL))
        (PROGN (LIST A B C D) (REVERSE (LIST A B C D)))))))

のように展開されます。

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20070919