2010年11月28日日曜日

たくさんの閉じ括弧を不快に思う人のためのリーダマクロ

本日(2010/11/27)はShibuya.lisp TT6に参加してきました。

Lisperばかりが70以上も集まるという、とても楽しいイベントでした。運営、発表者、会場、その他参加者の皆様、どうもありがとうございました。

内容についてはきっとどなたかがナイスな感じでまとめてくださるはずなので、帰宅して書いてみたネタを晒そうと思います。

今日のTTで Programming 2.0 という話題がでました。自分の中で要約すると、「おいコンパイラ、そのくらいのタイポでエラーをだすな。俺がやりたいことくらいわかるだろ?」という感じになりましたが、そのあたりに関連して、「Lispのネストした閉じ括弧をたくさん書くのが面倒、わかりにくい」というようなつぶやきが聞こえてきたので、なんとかしてみようと頑張ってみました。

(defparameter *unclose-parenthesis* 0)
(defparameter *super-kokka-sym* (gensym))
(defparameter *kokka-sym* (gensym))

(defun super-kakko-reader (stream ch)
(let ((*unclose-parenthesis* 0))
(loop :for s = (read stream t nil t)
:until (eq s *super-kokka-sym*)
:collect s)))

(defun super-kokka-reader (stream ch)
(when (> *unclose-parenthesis* 0) (unread-char ch stream))
*super-kokka-sym*)

(defun kakko-reader (stream ch)
(let ((*unclose-parenthesis* (1+ *unclose-parenthesis*)))
(loop :for s = (read stream t nil t)
:until (or (eq s *kokka-sym*)
(eq s *super-kokka-sym*))
:collect s)))

(defun kokka-reader (stream ch)
*kokka-sym*)

(set-macro-character #\{ #'super-kakko-reader)
(set-macro-character #\} #'super-kokka-reader)
(set-macro-character #\) #'kokka-reader)
(set-macro-character #\( #'kakko-reader)

「{」 で始まった式は、どれだけネストしていようと 「}」 が現れた時点で終端だと判断されます。

;; example

'{dotimes (i 3)
(dotimes (j 3)
(format t "~A x ~A = ~A~%" i j (* i j}

;; => (DOTIMES (I 3) (DOTIMES (J 3) (FORMAT T "~A x ~A = ~A~%" I J (* I J))))

最大の問題は、エディタのインデント支援の恩恵を受けられなくなるというところ。致命的ですね。

1 件のコメント:

  1. 昔のInterlispとかFranz lispには、super paren(超カッコ)というのがあって、]で全部を閉じることができました。ちなみに、先行する[がある場合は、]は対応する[までを閉じます。これに挑戦とかどうでしょう。

    返信削除