昨日の続き。
今日は、GNU Emacs Lispリファレンスマニュアルとか、moyashiさんに教えてもらった 優しい Emacs-Lisp 講座 も見ながら補足。
  • setq は変数が既にある場合も上書きするので、宣言だけしたい場合は defvar を使う。(.emacsで上書きするような設定変数などに使う)
    (setq hoge "def")
    (defvar hoge "abc" "hogeの説明") ; 変数hogeを宣言。
    (defvar moge "abc" "mogeの説明") ; 変数mogeを宣言。
    hoge ; 評価すると、def。
    moge ; 評価すると、abc
    
  • carとかcdrとかの操作は、リストに対するものではなくcons cellに対するものだった。cons cellはcarとcdrの二つの要素へのポインタを持つデータ構造のこと。リストは、入れ子になったcons cellのこと。
    '(a . b) ; car が a、cdr が bのcons cell
    '(a . (b . (c . nil))) ; (a b c) と同じ意味。
    
  • 連想リストは、cons cellのリスト
    (setq hoge-alist '((a . b) (c . d) (e . f))) ; 連想リスト
    (assoc 'c hoge-alist) ; 評価すると、(c . d)。cdrを取れば d が得られる。
    (setq hoge-alist '((a b) (c d) (e f))) ; リストも cons cellなのでこれもあり
    (assoc 'c hoge-alist) ; 評価すると、(c d)。cdrを取れば (d) が得られる。
    
  • lispのobjectは、複数の型に所属することができるので、あるobjectの型を一つに限定することはできない。特定の型に所属しているかどうかは調べることができる(instanceofとかtypeofみたいなものか)
    (type-of 1) ; 評価すると integer
    (type-of 1.1) ; 評価すると float
    (type-of "1") ; 評価すると string
    (type-of 'a) ; 評価すると symbol
    (type-of nil) ; 評価すると symbol
    (type-of '()) ; 評価するとsymbol
    (type-of '(a)) ; 評価すると cons
    (type-of [1 2 3]) ; 評価するとvector
    
    (consp ' (a . b)) ; 評価するとt 。cons cellかどうかを調べる。nilはnil。
    (atom 1) ; 評価するとt 。atomかどうかを調べる。cons cellでなければatom。nilだけはatomでありlistである。
    (listp '(a)) ; 評価するとt。cons cell又はnilどうかを調べる。
    (null nil) ; 評価するとt。nilかどうかを調べる。
    (arrayp [1 2 3]) ; 評価するとt。配列かどうかを調べる。
    (arrayp "abc") ; 評価するとt。文字列は文字の配列。
    (sequencep '(a b c)); 評価するとt。シーケンスかどうか調べる。
    (sequencep [1 b "3"]); 評価するとt。配列はシーケンス。
    (sequencep "abc"); 評価するとt。文字列は配列でありシーケンス。
    (symbolp 'a) ; 評価するとt。シンボルかどうかを調べる。
    (vectorp [1 2 3]); 評価するとt。
    (vectorp "abc"); 評価するとnil。文字列は配列だがvectorではない。
    
    emacs固有っぽいbufferとかframeや、char-table, bool-vector等は除いて図にしてみた。
    lispの型
  • 大雑把に言って、変数のscopeには、globalとlocalがあり、さらにバッファローカル、フレームローカルなどのemacs特有のものがある。
    (make-local-variable 'hoge) ; hogeをバッファローカルにする。
    (make-variable-buffer-local 'moge) ; moge を自動的にバッファローカルにするように印を付ける
    
    ※ 正直この部分は理解できていない。
  • hookにはノーマルフックとアブノーマルフックがある。ノーマルフックは、フックに引数も戻り値もない関数又はlambda式を渡すもので、アブノーマルフックは引数または戻り値があるもの。この辺になるとリファレンスマニュアルもだいぶ手抜き感と言うか、説明が足りない感じになってくる。
  • 適当に試したhookのサンプル
    (defun my-hook () "hook用の関数。arg0の4倍をlocal2にセットする"
      (setq local2 (* 4 arg0)))
    
    (defun func1 (arg0) "hook呼びだし関数その1"
      (let (local1 local2)
        (setq local1 (* 2 arg0))
        (setq local2 local1)
        (run-hooks 'func1-hook) ; func1-hookを呼びだし
        local2
        )
    )
    
    (defun func2 (arg0) "hook呼びだし関数その2"
      (let (local1 local2)
        (setq local1 (* 2 arg0))
        (setq local2 local1)
        (run-hooks 'func2-hook) ; func2-hookを呼びだし
        local2
        )
    )
    
    (defun func3 (arg0) "hook呼びだし関数その3"
      (let (local1 local2)
        (setq local1 (* 2 arg0))
        (setq local2 local1)
        (my-hook) ; my-hookを直接呼びだし
        local2
        )
    )
    
    (add-hook 'func1-hook (lambda () (setq local2 (* 3 arg0)))) ; hookにlambda式を追加
    
    (add-hook 'func2-hook 'my-hook) ; hookにmy-hookを追加
    
    (func1 3) ; 9 (lambda式によってarg0の3倍が結果になる)
    (func2 3) ; 12 (my-hookによってarg0の4倍が結果になる)
    (func3 3); 12 (my-hookによってarg0の4倍が結果になる)
    
    (remove-hook 'func2-hook 'my-hook)
    (func2 3) ; 6 (hookが呼ばれないのでarg0の2倍が結果になる)
    
なんでhookのところでこんなややこしいことをやったかと言うと、semi-1.14.6 の mime-display-text/plain と言う関数を読んでいて、(run-hooks 'mime-text-decode-hook) と言う場所があり、mime-text-decode-hookでぐぐったところ、2002 年 9月のよしだむメモと言うページがひっかかり、そこに載っていたhookで mime-display-text/plain の引数にアクセスしていたからです。
私が今まで使ってきた言語は、みんな lexical scope を持っていたので、emacs lisp のような dynamic scope が理解できていなかったのでした。
上記挙動を見てから、再度リファレンスマニュアルの10.9 変数束縛のスコープルール を読み直して、やっと意味が理解できたのでした。
誤解を恐れずに言えば、呼びだし元の変数が呼びだし先から見えると言うことですね。
だからノーマルフックとか言って、パラメータも戻り値もないhookが有り得るのかも知れません。
逆に言うと、hookは注意深く書かないと呼びだし元を簡単に破壊できてしまうと言うことになるのかな。

なんか予定と違って今回もemacs lispの言語仕様っぽい部分を進めましたが、次回はsemiのmime-display-text/plain の中で、パラメータがどうなっているのかを追ってみたいと思います。

カテゴリ

トラックバック(0)

このブログ記事を参照しているブログ一覧: emacs lispのお勉強(2)

このブログ記事に対するトラックバックURL: https://www.wizard-limit.net/cgi-bin/mt/mt-tb.cgi/2599

コメントする

このブログ記事について

このページは、falseが2011年4月 7日 10:05に書いたブログ記事です。

ひとつ前のブログ記事は「emacs lispのお勉強(1)」です。

次のブログ記事は「OpenTera(1)」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

広告

Powered by Movable Type 6.1.1