4

次のコードを検討してください。

    -module(abc).
    -export([f/1]).
    f(X) when (X==0) or (1/X>2) -> X+100;
    f(X) ->X.

およびabc:f(0)。結果0を取得しますが、なぜ1/Xは例外をスローしないのですか??

4

2 に答える 2

6

erlang ドキュメントのGuard Sequencesセクションには、次のように記載されています。

算術式、ブール式、短絡式、またはガード BIF の呼び出しが (無効な引数のために) 失敗した場合、ガード全体が失敗します。ガードがガード シーケンスの一部であった場合、シーケンス内の次のガード (つまり、次のセミコロンに続くガード) が評価されます。

つまり、ガード内の例外は、ガードが例外を発生させずに false を返したかのように扱われます。ガードの評価は、通常の erlang 式の評価とは少し異なります。

を呼び出すabc:f(0)と、式(0==0) or (1/0>2)が評価されます。この式は、ゼロによる除算のために「失敗」するため、ガードが一致せず、次の句が評価されて の答えが得られます0

このケースを元に戻したい場合100は、ガード シーケンスを使用するか、短絡ブール演算子を使用するという 2 つのオプションがあります。これらは

f(X) when X==0; 1/X>2 -> X + 100;
f(X) -> X.

f(X) when X==0 orelse 1/X>2 -> X + 100;
f(X) -> X.

それぞれ。どちらの書き方でもX==0個別の例外として評価され1/X>2、結果が true の場合は実行されません。

于 2012-08-14T06:06:05.547 に答える
4

ドキュメントについては、こちらをご覧ください。厳選して正確に言うには:

ガードは、式ではなく一連のテストで構成され、テストは成功または失敗します。テストにエラーが発生した場合、例外は生成されず、失敗するだけです。

ガードでは、で区切られたガードのシーケンスであるガードシーケンスを持つことができます。ガード;のいずれかが成功すると、ガードシーケンス全体が成功します。したがって、;代替ガードを分離します。

ガードでは、一連のガードテストをで区切ることができます,。ガード全体が成功するには、ガード内のすべてのテストが成功する必要があります。したがって、最も一般的な警備員は次のようになります。

f(...) when <test11>, <test12> ; <test21>, <test22> ; ... ->

では、ブール演算子についてはどうでしょうか。また、それらはテストとどのように関連している,;でしょうか。ガードテストでブール演算子を使用することは完全に合法であり、期待どおりに動作しますが、およびを使用することと同じではありません。特に失敗に関して。したがって、ブール式は1つのテストであり、2つのシーケンスではありません。さらに重要なのは(またはを使用して)、2つのガードのシーケンスではなく1つのガードテストです。したがって、エラーが発生すると、ガード全体が失敗します。エラーが発生すると、そのガードテストに失敗し、代替ガードが試行されます。,;<test11> and <test12><test11> or test<21>orelse<test11><test11> ; < test21><test11><test21>

それが@ShiDoiSiが言及したコメントのアドバイスの背後にある理由です。どちらを使用することもできますが、それらの意味と動作に注意してください。そして覚えておいてください:ガードは式ではなくテストで構成されています

PSなぜそれがこのようなものであるかについてのいくつかの歴史。非常に単純です。ブール演算子を使用するずっと前にガードがあったため、最終的にブール演算子を取得したとき、ガードのセマンティクスはすでに明確に定義されており、変更するには遅すぎました。ガードでブール式を許可すると、より正確なガードを作成できますが、ガードの本質を隠す傾向があります。

于 2012-08-14T14:58:17.340 に答える