Next: , Previous: , Up: 制御構造   [Contents][Index]


11.2 条件

条件による制御構造は候補の中から選択を行ないます。Emacs Lispは5つの条件フォームをもちます。ifは他の言語のものとほとんど同じです。whenunlessifの変種です。condは一般化されたcase命令です。condを汎用化したものがpcaseです(パターンマッチングによる条件を参照)。

Special Form: if condition then-form else-forms…

ifconditionの値にもとづきthen-formelse-formsを選択する。評価されたconditionが非nilならthen-formが評価されて結果がリターンされる。それ以外ならelse-formsがテキスト順に評価されて最後のフォームの値がリターンされる(ifelseパートは暗黙のprognの例である。順序を参照)。

conditionの値がnilelse-formsが与えられなければ、ifnilをリターンする。

選択されなかったブランチは決して評価されない — 無視される — ので、ifはスペシャルフォームである。したがって以下の例ではprintが呼び出されることはないのでtrueはプリントされない。

(if nil
    (print 'true)
  'very-false)
⇒ very-false
Macro: when condition then-forms…

これはelse-formsがなく、複数のthen-formsが可能なifの変種である。特に、

(when condition a b c)

は以下と完全に等価である

(if condition (progn a b c) nil)
Macro: unless condition forms…

これはthen-formがないifの変種です:

(unless condition a b c)

は以下と完全に等価である

(if condition nil
   a b c)
Special Form: cond clause…

condは任意個数の選択肢から選択を行なう。cond内の各clauseはリストでなければならない。このリストのCARconditionで、(もしあれば)残りの要素はbody-formsとなる。したがってclauseは以下のようになる:

(condition body-forms…)

condは各clauseのconditionを評価することにより、テキスト順でclauseを試みる。conditionの値が非nilならそのclauseは成り立つ。その後にcondはそのclauseのbody-formsを評価して、body-formsの最後の値をリターンする。残りのclauseは無視される。

conditionの値がnilならそのclauseは失敗して、condは次のclauseに移動してそれのconditionを試みる。

clauseは以下のようにも見えるかもしれない:

(condition)

conditionがテストされたときに非nilなら、condフォームはconditionの値をリターンする。

すべてのconditionnilに評価された場合 — つまりすべてのclauseが不成立なら、condnilをリターンする。

以下の例はxの値が数字、文字列、バッファー、シンボルなのかをテストする4つのclauseをもつ:

(cond ((numberp x) x)
      ((stringp x) x)
      ((bufferp x)
       (setq temporary-hack x) ; 1つのclauseに
       (buffer-name x))        ; 複数bodyフォーム
      ((symbolp x) (symbol-value x)))

前のclauseが不成立のとき最後の条項を実行したいときがよくある。これを行なうには(t body-forms)のように、conditionの最後のclauseにtを使用する。フォームttに評価され決してnilにならないので、このclauseが不成立になることはなく最終的にcondはこのclauseに到達する。たとえば:

(setq a 5)
(cond ((eq a 'hack) 'foo)
      (t "default"))
⇒ "default"

このcond式はaの値がhackならfoo、それ以外は文字列"default"をリターンする。

すべての条件構文はcondifのいずれかで表すことができます。したがってどちらを選択するかはスタイルの問題になります。たとえば:

(if a b c)
≡
(cond (a b) (t c))

変数のバインドとあわせて条件を使うと便利かもしれません。変数の計算を行って、その後もし値が非nilなら何かしたいというのはよくあることです。これを行うには、たとえば以下のように単にそのまま記述すればよいのです:

(let ((result1 (do-computation)))
  (when result1
    (let ((result2 (do-more result1)))
      (when result2
        (do-something result2)))))

これはパターンとしては非常に一般的なのでEmacsではこれを簡単に行って、かつ可読性を向上させるためのマクロがいくつか提供されています。上記のコードは以下のように記述することができます:

(when-let ((result1 (do-computation))
           (result2 (do-more result1)))
  (do-something result2))

このテーマにはバリエーションがいくつかあり、以下にそれらを概略します。

Macro: if-let spec then-form else-forms...

spec内のバインディングを、let* (ローカル変数を参照)のようにそれぞれ順番に評価して、値がnilになるバインディングがあれば停止する。すべて非nilならthen-form、それ以外ではelse-formsの最後のフォームの値をリターンする。

Macro: when-let spec then-forms...

if-letと同様だがelse-formsがない。

Macro: while-let spec then-forms...

when-letと同様だが、spec内のバインディングがnilになるまで繰り返す。リターン値は常にnil


Next: 組み合わせ条件の構築, Previous: 順序, Up: 制御構造   [Contents][Index]