条件式の「and」と「when」


13

これは、この回答に対するコメントのフォローアップです。次のコードは同等のようです:

(and a b)

(when a b)

もちろんand:あなたはより多くの条件に置くことができます(and a b c d)手段を(when (and a b c) d)

私はwhen分岐を表現するためだけに使用する傾向があります。実際の違いはありますか?どちらを使用するのが良いですか?

EmacsのCソースは手元にありません。andC関数です。whenはに展開されるマクロでありif、それ自体はC関数です。


「もちろんand lets」は「もちろん `and` lets」にする必要がありますが、それは2文字の変更であり、編集は許可されていません。オーバーライドはありません。
ハーベイ

回答:


17

TL; DR: when副作用に関するもので、and純粋なブール式用です。

あなたは気づいた、としてandおよびwhen構文が異なるだけで、それ以外は全く同じです。

ただし、構文の違いは非常に重要です。最初の引数形式以外のすべてをwhen暗黙的にラップしprognます。 prognは本質的に必須の機能です。返される値はすべて破棄し、副作用についてのみ最後のボディフォームを除くすべてを評価します。

このようにwhen、命令型も同様です。主な目的は、副作用のあるフォームをラップすることです。なぜなら、最後のフォームの値だけが実際に身体にとって重要だからです。

and一方、純粋な関数であり、その主な目的は、指定された引数形式の戻り値を調べることです。progn引数のいずれかを明示的にラップしない限り、すべての引数形式の値は重要であり、値は無視されません。

したがって、間の本当の違いandとはwhen文体です:あなたが使用してand、純粋なブール式のために、そしてwhen副作用フォームの周りにガードを配置します。

したがって、これらは悪いスタイルです:

;; `when' used for a pure boolean expression
(let ((use-buffer (when (buffer-live-p buffer)
                    (file-exists-p (buffer-file-name buffer)))))
  ...)

;; `and' used as guard around a side-effecting form
(and (buffer-file-name buffer) (write-region nil nil (buffer-file-name buffer)))

そして、これらは良いです:

(let ((use-buffer (and (buffer-live-p buffer)
                       (file-exists-p (buffer-file-name buffer)))))
  ...)

(when (buffer-file-name buffer)
 (write-region nil nil (buffer-file-name buffer)))

一部の人々はこれに同意せず、喜んでand副作用を防ぐために使用していることを知っていますが、これは本当に悪いスタイルだと思います。理由は次のとおりです。構文が重要です。そうでなければif、Emacs Lispで意味的に本当に必要な唯一の条件付きフォームであるを使用するだけです。他のすべてのブール形式および条件付き形式は、に関して記述できますif


2
IMO(つまり、私が使用しているスタイル)and、戻り値を気にすることです。必ずしも副作用を使用するわけではありません。私のプログラムが戻り値を気にする場合は、を使用しますand。そうでない場合は、を使用しますwhen。IOW、私は副作用のためwhen だけに使用しますが、私prognはargsの1つでa を使用するかもしれませんand。それはない、それかどうかについては、戻り値の問題かどうかについてですだけでは問題。
ドリュー

5
and私が知っているどのLispの関数でもありません。Emacs Lispではそれは特別な形であり、Common Lispではそれはマクロです。単に短絡動作が期待されるからです(常に引数を評価するため、関数で達成することは不可能です)。
マークカルポフ

2
@lunaryorn、はい、それは実際に関連性はありませんが、それは本当ですので、そうでandないときに関数であると書くのは間違っていると思います。質問に事実がどの程度関連しているかは関係ありません。常に正しい用語を使用する必要があります。それだけです。
マークカルポフ

2
さて、「すべての引数形式の値が重要である」とその解釈が一致するとは思いません。フォームは、その値を破棄するためだけに評価されることはないと言うことで、より適切に表現できます。
ハラルドハンシュオルセン

3
ややOTですが、違いはnil、「偽」、「空のリスト」、「ボイド」などのすべてを意味するようにしゃべらないLispの文体以上のものです。たとえば、SchemeとRacketでは、whenis void(つまり、「意味なし」)に対して、andそれは#f(「false」)です。これはElispにとってN / Aですが、Lispジェネラリストが検討するかもしれないものです。
グレッグヘンダーショット

4

それ(and a b)を言うことから始めましょう、そして(when a b)あなたの例では同じことをします:最初aが評価されます。b場合に評価されaている

しかし andwhenさまざまな用途に使用されます。

  • あなたは使用し(and a b)返すために真の#を BOTH場合abされている(またはnil以外)。とnilそうでありません。

  • を使用する(when a b)か、より正確にするには、

    (when a
       ;; do something like b
       )

    あなたが「B」のコードを実行したいとき場合に限りがaある


次にwhenand一緒に使用する例を示します。

(when (and a b)
   (do-c))

上記、機能はdo-cONLY BOTH場合に呼び出されるabされている


研究のための参考文献

#trueへのすべての参照は、ブール値TRUEを参照します


3
andtすべての引数が非nilの場合は返されませんが、最後の引数の値は返されます。
意味のあるユーザー名

1
によってt、私はブールTRUEまたは非nilを意味しました。ありがとう、私の答えでそれを明確にします。
カウシャルモディ

あなたの答えは、私がすでに質問で述べたことよりもはるかに先に進むとは思わない。私は両方が何をするかを知っています、そして、あなたが与える最後の例はすでに私の質問((when (and a b) c))にあります。さらに、それが実際に一般的にどのように使用されているかについての部分は、実際にどのように使用されているかandwhen示唆していますが、この質問の基本は、使用方法が異なることが多いという事実でした(たとえば、私の質問でリンクした答えを参照)。
クレメント

純粋に機能的な構造の観点から、whenは非終了評価用あり、直接シンボルおよびブールロジック用です。関数型プログラミングにはこの区別が必要です。命令型プログラミングはこれを回避します。
Emacsユーザー

1
「真のブール値」が単なる「真」よりも明確だとは思いません。
YoungFrog
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.