2015年1月19日月曜日

Emacs Lisp を少し勉強した


1 Emacs Lisp を少し勉強した   gblog



Emacs Lisp のコードを読むときに知らなくて困った(多分)基本的な所をメモ.

困ったときに調べたものだけメモしているので,網羅はしてない.




1.1 コンスセル



「CARスロットおよびCDRスロットと呼ばれる 2つのポインタから成るオブジェクトです。」らしい.

「各スロットは、任意のLispオブジェクトを指すことができます。」

ドット記法とかで表現する.

(A . B) と書くと,A がCARスロット,B がCDR スロット



参考ページ:

GNU Emacs Lispリファレンスマニュアル: Cons Cell Type







1.2 cons obj1 obj2



obj1 とobj2 から成るコンスセルを作る関数.

(cons 1 2) => (1 . 2)





1.3 リスト



リストはコンスセルの入れ子構造.

(1 2 3) と表示する.

この実態は,CARスロットが1, CDR スロットが(2 3) のコンスセル.

2と3 が要素のリスト(2 3) の実態は CARスロットが2, CDR スロットが(3) のコンスセル

3だけが要素のリスト(3) の実態は CAR スロットが3, CDR スロットが空リストの()

ドット表記だと(1 . (2 . (3 . ())

(cons 1 (2 3)) => (1 2 3)

(cons 1 ()) => (1)

また,空リスト() はnil とも書く

つまり,

(cons 1 nil) => (1)





1.4 関数car, cdr



コンスセルのCAR スロットを取り出すのがcar 関数,CDR スロットを取り出すのがcdr 関数.

リストに適用すると,以下のような感じ.

(car '(0 1 2)) => 0

(cdr '(0 1 2)) => (1 2)





1.5 シングルクォートは何?



car やcdr の例では'(0 1 2) とリストの前に「'」がついている.

これは,リストを評価しないようにするためのものらしい.

リストを評価するとは,リストのCAR スロット(第一要素)を関数名,第二引数以降を関数の引数として,計算するということ.

Lisp は(0 1 2) とだけ書いて実行すると,0 を関数名,1 を第一引数,2 を第二引数として計算しようとするらしい.

これをせずに,リストとしてそのまま置いておくために,シングルクォートをつける.

関数名や変数名の前に「'」をつけるのも同じ理由のようである.



参考ページ:

Programming in Emacs Lisp: List Processing



また,別の説明で,おそらくより厳密な説明が以下のリンクにある.

Emacs Lisp

これをちゃんと理解するためには,シンボルというものを理解しないといけないらしい.

また,シンボルなるものの構造については以下のリンクが詳しいと思う.

GNU Emacs Lispリファレンスマニュアル: シンボル

このあたりの理解は今後の課題.





1.6 let



ローカル変数を定義して,最後のリストを評価する.



(let (ローカル変数の定義のリスト) フォーム1 … フォームn)



ローカル変数の定義のリストは以下の構文

((ローカル変数名1 初期値1) ローカル変数名2 … (ローカル変数名n 初期値n))

(ローカル変数名1 初期値1) と言うリストは,ローカル変数名1 が初期値1 で初期化することを示す.

一方,ローカル変数2 とだけ書いていると,ローカル変数2 はnil で初期化する.



フォームとは,Emacs Lisp のコードと思えばいいのかな?

let 全体の戻り値は,最後のフォーム(フォームn) の戻り値になる.



例:

(let ((x 3)) x) => 3

(let ((x 3) (y 2)) x y) => 2 ;; 最後のフォームがlet の戻り値になる

(let ((x 3) (y 2)) (+ x y)) => 5

(let ((x 3) y (z 4)) (list x y z)) => (3 nil 4) ;; (list x y z) はx y z を要素とするリストを返す






1.7 スペシャルフォーム(special form) とマクロ



普通,リストの形式で書いて実行すると,全てのリストが評価される.

しかし,例外があるらしく,それがspecial form というらしい.

先のlet はその一つ.

(let ((x 3) (y 2)) (+ x y)) の(x 3) はリストだが,これを関数として評価していない(したらx なんて関数はないとエラーが出るはず)

一方,一番後ろの(+ x y) は評価されている.

このように,let の引数に関しては,一番後ろしか評価しない,ということになっているようである.

他にも,値を変数に代入するsetq などがそうらしい.



また,スペシャルフォームという言葉を調べていると,マクロという言葉もよく見かける.

マクロは,ユーザー定義のスペシャルフォームらしい.

参考ページ:

スペシャルフォームとマクロ - by shigemk2






1.8 dolist



実は,このブログの内容は,dolist のサンプルコードがわからなくて調べだしたのがきっかけ.

つまり,今回のブログはここがゴール.



dolist もlet のようにスペシャルフォーム.

構文は以下.

(dolist (ローカル変数 リスト [戻り値]) フォーム1 … フォームn)



リストの要素を一つずつローカル変数に代入してフォーム1 からフォームn の処理を繰り返す

python とかでいうforeach 的なやつ.

戻り値を設定しないと,dolist の戻り値はnil になる.

また,戻り値に未定義の変数は使えないので,予め定義する必要がある.

例:

(let ((sum 0)) ;; 戻り値に使う変数を定義

(dolist (x '(1 2 3) sum)

(setq sum (+ x sum)))) => 6






--
My Emacs Files At GitHub