パターンマッチングとガードの違いは何ですか? 質問する

パターンマッチングとガードの違いは何ですか? 質問する

私は Haskell と関数型プログラミング全般について非常に初心者です。私の質問はかなり基本的なものです。パターン マッチングとガードの違いは何ですか?

パターンマッチングを使用する関数

check :: [a] -> String
check [] = "Empty"
check (x:xs) = "Contains Elements"

ガードを使用する関数

check_ :: [a] -> String
check_ lst
    | length lst < 1 = "Empty"
    | otherwise = "Contains elements"

パターン マッチングとガードは基本的に同じであるように見えます。どちらも条件を評価し、true の場合はそれにフックされた式を実行します。私の理解は正しいでしょうか?

この例では、パターン マッチングまたはガードを使用して同じ結果を得ることができます。しかし、ここで重要なことを見逃しているような気がします。常にどちらかを他方に置き換えることはできますか?

パターン マッチングがガードよりも優先される例、またはその逆の例を誰か挙げてもらえますか?

ベストアンサー1

実際のところ、それらは根本的にかなり異なります。少なくとも Haskell ではそうです。

ガードはよりシンプルで柔軟性があります。基本的には、一連の if/then 式に変換される特別な構文です。ガードには任意のブール式を入れることができますが、通常の でできないことは何もできませんif

パターンマッチは、さらにいくつかの機能も備えています。データを分解する唯一の方法、 そして彼らがスコープ内で識別子をバインドするガードが式と同等であるのと同じ意味でif、パターン マッチングは式と同等ですcase。宣言 (最上位レベルまたは式のようなものlet) もパターン マッチングの形式であり、「通常の」定義は単純なパターン、つまり単一の識別子と一致するものです。

パターン マッチは、Haskell で実際に処理が行われる主な方法でもあります。パターン内のデータを分解しようとすることは、評価を強制する数少ない方法の 1 つです。

ちなみに、トップレベルの宣言では実際にパターン マッチングを行うことができます。

square = (^2)

(one:four:nine:_) = map square [1..]

これは、関連する定義のグループの場合に役立つことがあります。

GHCもViewPatterns拡張機能を提供しますこれは、ある意味では両方を組み合わせたもので、バインディング コンテキストで任意の関数を使用し、その結果に対してパターン マッチを行うことができます。もちろん、これは通常の機能に対する単なる構文上の糖衣にすぎません。


どこで何を使うかという日常的な問題については、大まかなガイドを以下に示します。

  • 1 つまたは 2 つのコンストラクターの深さで直接一致できるものには、必ずパターン マッチングを使用してください。この場合、複合データ全体は気にしませんが、構造の大部分は気にします。@構文を使用すると、全体の構造を変数にバインドしながらパターン マッチングも実行できますが、1 つのパターンでその操作をやりすぎると、すぐに見苦しく読みにくくなります。

  • パターンにきちんと対応しないプロパティに基づいて選択を行う必要がある場合、たとえば 2 つのInt値を比較してどちらが大きいかを調べる場合は、必ずガードを使用してください。

  • 大きな構造の奥深くから数個のデータだけが必要な場合、特に構造全体を使用する必要がある場合は、ガードとアクセサ関数の方が、 や でいっぱいの巨大なパターンよりも読みやすくなり@ます_

  • 異なるパターンで表される値に対して同じことを行う必要があるが、それらを分類するための便利な述語が必要な場合は、ガード付きの単一の汎用パターンを使用する方が通常は読みやすくなります。ガードのセットが網羅的でない場合、すべてのガードに失敗したものは、次のパターン (ある場合) にドロップされることに注意してください。したがって、一般的なパターンを何らかのフィルターと組み合わせて例外的なケースをキャッチし、他のすべてに対してパターン マッチングを実行して、必要な詳細を取得できます。

  • パターンで簡単にチェックできるものには、絶対にガードを使用しないでください。空のリストのチェックは典型的な例です。そのためにはパターン マッチを使用します。

  • 一般的に、疑問がある場合は、デフォルトのパターン マッチングに固執してください。通常はその方が便利です。パターンが非常に醜くなったり複雑になったりした場合は、他の書き方を検討してください。ガードを使用する以外にも、部分式を別の関数として抽出したり、式をcase関数本体内に入れて、パターン マッチングの一部をメイン定義から外したりする方法があります。

おすすめ記事