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 |

2008-02-09

EmacsのCommon Lispインデント

| 04:02 | EmacsのCommon Lispインデント - わだばLisperになる を含むブックマーク はてなブックマーク - EmacsのCommon Lispインデント - わだばLisperになる

EmacsでCommon Lispのコードを編集する時には、cl-indentを使用しているのですが、割とprogと、loopの時に思ったようにインデントしてくれないので、色々調整してみているのですが、どうも簡単な方法がみつからず結局、cl-indent.elの関数を変更することにしてみました。とはいえ、後で自作の関数を読み込みさせるだけですが…。

どういう風にインデントされて欲しいかというと、

(loop :for i = 0 :then (incf i)
      :if (< 10 i)
	:do (print "End.")
            (return res)
      :else
	:collect i :into res
      :end)

(prog (foo)
      (setq foo '(foo bar baz))
   L  (cond ((endp foo) (return)))
      (pop foo)
      (go L))

みたいな感じです。まあ、いまどきPROG使う人もいないと思うんですが、PROGの時はずらっと括弧の位置が揃ってると気持ち良いんですよね。

LOOPはとりあえず、2行目以降、7カラム目に揃ってれば良いんですが、doのときに、2つ字下げしてるのをLispマシンのマニュアルで発見したので、そういう風なのも良いかなと。

とりあえず、無理矢理な感じですが、設定をでっち上げました。

;; Common Lisp - インデント関係の設定
;; tagbody / prog
(setq lisp-prog-tag-indentation 3
      lisp-prog-tag-body-indentation 6
      lisp-tag-indentation 1
      lisp-tag-body-indentation 3)

;; lisp-indent-tagbodyをほんのちょっと改造
(defun lisp-indent-prog (path state indent-point sexp-column normal-indent)
  (if (not (null (cdr path)))
      normal-indent
    (save-excursion
      (goto-char indent-point)
      (beginning-of-line)
      (skip-chars-forward " \t")
      (list (cond ((looking-at "\\sw\\|\\s_")
                   ;; a tagbody tag
                   (+ sexp-column lisp-prog-tag-indentation))
                  ((integerp lisp-prog-tag-body-indentation)
                   (+ sexp-column lisp-prog-tag-body-indentation))
                  ((eq lisp-prog-tag-body-indentation 't)
                   (condition-case ()
                       (progn (backward-sexp 1) (current-column))
                     (error (1+ sexp-column))))
                  (t (+ sexp-column lisp-body-indent)))
            (elt state 1)))))

(put 'prog 'common-lisp-indent-function 'lisp-indent-prog)

;; loop
(defun common-lisp-loop-part-indentation (indent-point state)
  "Compute the indentation of loop form constituents."
  (let* ((loop-indentation (save-excursion
			     (goto-char (elt state 1))
			     (current-column))))
    (goto-char indent-point)
    (beginning-of-line)
    (cond ((looking-at "^\\s-*:?\\(do\\|collect\\)\\(\\s-\\|\(\\)\\(\\s-*\\|;\\)")
	   (+ loop-indentation lisp-loop-keyword-indentation 2))
	  ((looking-at "^\\s-*\\(:?\\sw+\\|;\\)")
	   (+ loop-indentation lisp-loop-keyword-indentation))
	  (t
	   (+ loop-indentation lisp-loop-forms-indentation))))))

(setq lisp-loop-forms-indentation 6
      lisp-loop-keyword-indentation 6
      loop-indentation 6)

(put 'loop 'common-lisp-indent-function 'common-lisp-loop-part-indentation)

;; (cl-indent 名前 手本)
(defun cl-indent (sym indent)
  (put sym 'common-lisp-indent-function
       (if (symbolp indent)
	   (get indent 'common-lisp-indent-function)
	 indent)))

(cl-indent 'iterate 'let)
(cl-indent 'collect 'progn)
(cl-indent 'mapping 'let)
(cl-indent 'define-syntax 'let)

PROGは、まあまあこれでできたのですが、LOOPが

(loop :for i = 0 :then (incf i)
      :if (< 10 i)
	:do (print "End.")
      (return res)
      :else
	:collect i :into res
      :end)

のようになるので、doの範囲を自分で字下げしないといけないという…。あと、lisp-indent-lineでは字下げしてくれますが、indent-regionとか、indent-sexpでは、doとかcollectは字下げしてくれないので、これも面倒だという。

何か簡単に調整してくれるEmacs Lispとか配布されてないんですかねー。

皆さんはどうされているのでしょう。

その時代のパラダイム的なものとLISP

| 01:50 | その時代のパラダイム的なものとLISP - わだばLisperになる を含むブックマーク はてなブックマーク - その時代のパラダイム的なものとLISP - わだばLisperになる

プログラミングの初心者がこんなこと考えていて、またブログに書いてもしょうがないとは思うのですが、ふと、現在大多数の人が考えているLISP像というは、謂わば、Schemeのことなんじゃないかなと、思えてきました。

なんというか、今となっては、Unixといえば、Linuxのこと、みたいな、そんな感じで。勿論私は、Unixといえば、Linuxとは思ってないですが(笑)

レキシカルスコープじゃないLISPとか、GO TOがあったりとか、ガンガン代入文を使ったスタイルとか、それと、ちょっと違うかもしれないけれど、見た目がS式じゃなかったりとか。

そういうのは大多数の人にとってLISP的じゃないんじゃないかなと。

  • レキシカルスコープ

レキシカルスコープに関しては、Schemeが持ち込んで、その後のCommon Lispにも採用されました。

その前(1980年代初頭)は、ダイナミックスコープの処理系が主流で、MACLISP、Zetalisp、Franz Lisp(勿論Allegro CLじゃないです)等、ダイナミックスコープです。ただ、コンパイルした関数は、レキシカルスコープだったりしますが…。

  • GO TO

GO TOについては、これも70年代後半位から、GO TOの機能を提供していたPROGの使用が減少し、CLの登場で決定的になりました。ちなみにGO TOは後から取り入れられたものではなく、最初から存在します。

これについては、構造化プログラミングスタイルの啓蒙ってことも大きいとは思うのですが、その他には、PROGの果して来た機能が徐々に分解されて提供されるようになったということもあると思います、具体的には、progn、do、let、tagbody、block、等に分解されて行ったように見えます。これ以前のスタイルでは、lambdaとprogの組み合わせが主なものだったようです。主義というよりも、なんとなくPROGで書くより便利なので、そっちに乗り換えられていったという気がします。

構造化プログラミングスタイル云々より以前からLISPはあった訳なので、この辺はなんとなく独特な気がします。

また、GOTOとはいえ、関数内に限られているので、そんなに飛べる範囲は広くないので、そんなに恐しいことにはならないというのもあるでしょう。とはいえ、1つの定義で500行の壮観なGO TO多用型の関数もあったりしますが(笑)

  • ガンガン代入文を使ったスタイル

ガンガン代入文を使ったスタイルについては、割とCommon Lispでも見られると思いますが、Schemeじゃ好かれないですよね(笑)

  • プログラムの書式がS式じゃない

比較的ユーザに近い層で、S式にマッピングされたり、根底の考えがS式なのであれば、やっぱりLISPっぽくなる気がします。Dylanとか、やっぱりLISPな気がしますし、M式とか、CGOLとかユーザが直接S式を書かない方式もありました。

そういう意味で、Matz Lispは、LISPっぽいのかどうか、興味があります。自分はろくにRubyは読み書きできないのでなんとも言えないのですが、S式を感じられるなら、LISPなんじゃないでしょうか。今の私のレベルでは、あんまり感じないんですけども…。

それで何が言いたかったかということなのですが、書きたいように書けるのがLISPの良いところなんじゃないかなあ、と。

BASICみたいなスタイルで書いても良いし、SmallTalkみたいに書いても良いし、Schemeみたいに書いても良いし、Perlみたいに書いても良いし、個人のスタイルを変更しないで書くことが楽だと思います。

極論すれば、LISPには文法がないですが、限定されたスタイルもない、みたいな。

という、なんともまとまりのないエントリですいません。

もちろん、私は趣味プログラマだから、この考えは成り立つんだと思います。