“ダブルコンス”をネストできますかパターンマッチ?
-
05-07-2019 - |
質問
追加の検証機能に合格した数字のみに一致するようにパターンを強化したい。
let (|IsValid|_|) n = ...
let (|Nil|One|Two|) (l : int list) =
match l with
| a :: b :: t -> Two(a + b)
| a :: t -> One(a)
| _ -> Nil
「1つ」のケースは簡単です:
| IsValid(a) :: t -> One(a)
「2」のケースは私には明らかではありません。数値の合計を検証する必要があります。 when-guardを使用せずにこれを実行できますか?
...
編集:次のようなwhen-guard(boolを返すisValid関数を使用)を使用できます:
| a :: b :: t when isValid a + b -> Two(a + b)
これは、単にパターンを照合するよりもエレガントではありません。さらに悪いことに、a + bは2回適用されます。
また、これは実際のコードの単純化されたバージョンであることに注意してください(たとえば、リストのさまざまな長さに対して単純に一致させようとはしていません)。
解決
私の解決策:" helper"を追加します親パターンで使用するように設計された戻り値を持つ認識機能:
let (|MatchTwo|_|) = function
| a :: b :: t -> Some(a + b :: t)
| _ -> None
次のように使用します:
let (|Nil|One|Two|) (l : int list) =
match l with
| MatchTwo(IsValid(a) :: t) -> Two(a)
| IsValid(a) :: t -> One(a)
| _ -> Nil
他のヒント
行うとき:
| a :: b :: t -> ...
リスト内の2つの要素を必ずしも一致させる必要はありません。 t
ではなく []
を使用して、2つの要素を正確に一致させることをお勧めします- t
は、より多くの要素のリストにすることができます。
| a :: b :: [] -> Two (a+b)
これにより、2つの要素のみが一致することが保証されます。エラーチェックは無料です。関数が0、1、または2つの要素のリストのみを受け入れることを期待している場合でも、これを行うことをお勧めします。だから、
編集:
let (|MatchTwo|_|) = function
| a :: b :: t -> Some(a + b :: t)
| _ -> None
let (|Nil|One|Two|) (l : int list) = match l with
| MatchTwo(IsValid(a) :: t) -> Two(a)
| IsValid(a) :: t -> One(a)
| _ -> Nil
ええ、 when
を使用します。これは混乱です。パターンマッチングは、マッチ内で関数を適用することは実際には意味がありません。しかし、私が以前言及したことを考慮に入れてください。例に基づいて:
match l with
| a :: b :: t when isValid (a+b) -> Two (a+b)
| a :: t when isValid (a) -> One a
| _ -> Nil
2番目のパターンは、最初のパターンでisValidがfalseの場合、1つより長いリストに一致します。パターンをできるだけ具体的にしてください。1つの要素に一致させる場合は、それを実行してください。
aとbの組み合わせに使用する演算(この場合は+)の計算が高価な場合、isValidをテストして返す前に when
を削除し、letステートメントを使用する必要がありますバリアント型。