[F#]パターンマッチング

他の多くの関数型プログラミング言語と同様に、F#はパターンマッチングをサポートしています。 FPに慣れていない人は、FPが大幅に改善されたバージョンのスイッチであると想像できます。


コードに移動します。

rec階乗n =
nに一致
| 0 | 1- > 1
| _- > n *階乗( n- 1 )

このコードは、再帰的階乗関数を定義します。 ご覧のとおり、スイッチに非常によく似ています。

ペア、トリプルなど


let ( + ) vec Multiplier =
vec を x、y と 一致させる ->
x *乗数、y *乗数

ここでは、要素は値のペア(タプル)にマッピングされます。 したがって、xはペアの最初の要素、y-2番目の要素の値を取ります。 xとyは新しい値記述子であることに注意してください。 プログラムの初期にxという名前の別の値が記述されていた場合、ブランチの終わりまで新しく入力された値によって非表示になります。 新しい説明を導入しないために、最初のコード例で行われたように、アンダースコアを使用する必要があります。 サンプル内で必要な回数発生する可能性があり、実際にはプレースホルダーです。

リスト



let sum = function
| [ ] -> 0
| 頭::尾->
ヘッド+サムテール

この頭字語は次と同等です

合計値=
値と 一致
| [ ] -> 0
| 頭::尾->
ヘッド+サムテール

唯一の違いは、valueという名前の記述子が入力されないことです。

最初のサンプル[]は、空のリストに対応しています。 2番目のサンプルでは、​​リストを2つの部分、ヘッド(最初の要素)とテール(他のすべての要素のリスト)として説明しています。 頭と尾の代わりの名前は任意に選択できます。 それらのスコープはブランチの終わりまでです。

リストの上部から複数のアイテムを一度に分離できます。 el1 :: _ :: el3 ::尾

複数の値


サンプルを比較する場合、ペアをコンポーネントに分割できるだけでなく、値のペアを操作することもできます。

ホスト、ポートと 一致
| 「Microsoft.com」 、 80- >許可
| 「Warezzz.ws」 、 80- >拒否
| _- >進む

パターンマッチングを使用して、タイプを決定できます(動的)。

obj と 一致
| : ? str としての文字列-> "String!"
| : ? 整数としての Int32- > "Int!"
| _- > 「それは何ですか?」

追加条件


let rec hasNegative = function
| [ ] -> false
| ヘッド::ヘッド< 0- > trueの 場合のテール
| _ ::テール-> hasNegativeテール

サンプルの比較は順番に行われるため、サンプルの1つが表示されると、後続のサンプルは比較されなくなります。 これにより、最後のブランチでhead> = 0の場合に書き込む必要はありません。

アクティブなパターン


この機能はおそらくF#に固有のものです。 独自のマッチング方法を定義する機会が与えられます。 簡単な例を見てみましょう。

let ( | Odd | Even | ) = 関数
| x x 2 = 0の場合 ->偶数
| _- >奇数

と一致する 10
| 奇数-> "oO"
| 偶数-> ":)"

マッチング方法は、本質的に特別な方法で定義された関数です。 彼女には名前はありませんが、サンプルのペアがすぐに識別されます-奇数と偶数。

簡単な選択に加えて、任意に整理できます。 これには部分一致法が使用されます。

let ( | Prime | _ | ) value =
Composite = Listとします。 exists ( fun n- > value%n = 0 ) [ 2 。 。 int ( Math。Sqrt ( value ) ) ]
複合でない場合は、 Some ( value )
それ以外はなし

nに一致
| プライムx- > sprintf "input%d is prime!" X
| x- > sprintf 「この値は特別ではありません」

これはかなり単純な例です。 もっと複雑なものを見てみましょう。

タイプ StackItem =
| int32のint
| 文字列の文字列

let ( | Add | _ | ) = function
| オペコード 追加、Int ( a ) :: Int ( b ) :: stackRest- >
Some ( Int ( a + b ) :: stackRest )
| オペコード 追加、文字列( a ) ::文字列( b ) :: stackRest- >
Some (文字列( a + b ) :: stackRest )
| オペコード 追加、_- >
InvalidProgramException ( "無効な引数の追加" ) | >上げる
| _- >なし

let ( | Sub | _ | ) = 関数
| オペコード 追加、Int ( a ) :: Int ( b ) :: stackRest- >
Some ( Int ( a-b ) :: stackRest )
| オペコード 追加、_- >
InvalidProgramException ( "無効なサブ引数" ) | >上げる
| _- >なし

オペコードcurrentStack =を計算させます
opcode、currentStack と 一致
| 追加( newStack ) | Sub ( newStack ) -> newStack
| _- > InvalidProgramException ( sprintf "invalid opcode%A" opcode )


マッチングの部分的な方法では、次のように大まかに説明する特別なオプションタイプ(Nullable analog)を使用します。
タイプ Option 'a =
| なし
| いくつかの

したがって、オブジェクトがパターンに一致しないことを示すために、Noneが返されます。 この場合、サンプルをSomeパラメーターとして適用した結果も返し、それを使用します(newStack)。

まとめ


ご覧のとおり、パターンマッチングは非常に便利です。 C#ではなくF#を選択するのは、ほとんど唯一の理由です(翻訳時に使用するのが非常に便利です。スタックマシンでのコード例を参照してください)。 多くのユースケース、コンパクトなコード、およびそのマッチング方法による拡張性-これらすべてにより、F#でのパターンマッチングは非常に魅力的です。

PSすべてのコード例に正しい引用符が付いているわけではないという事実をおIびします。 habraparserまたはコード強調ツールのいずれかがこの残酷な冗談を演じました。

Source: https://habr.com/ru/post/J89912/


All Articles