リストをフィルタリングするだけの場合、最も簡単なオプションは、function
標準のパターンマッチングを作成するために使用することです。
[ Foo; Bar; Foo ]
|> List.filter (function Foo -> true | _ -> false)
ケースをチェックしてから何か他のことを行う、より複雑なジェネリック関数を作成したい場合、最も簡単なオプション(一般的に機能します)は、true
またはfalse
:を返す述語を取ることです。
let is cond item =
if cond item then
true
else
false
// You can create a predicate using `function` syntax
is (function Foo -> true | _ -> false) <argument>
特定の例では、どのケースにもパラメーターがない、識別された共用体があります。これはおそらく非現実的な単純化ですが、パラメーターのない識別された共用体のみを気にする場合は、ケースを値として使用して比較することができます。
let is case item =
if case = item then
true
else
false
// You can just pass it 'Foo' as the first parameter to
// `is` and use partial function application
[ Foo; Bar; Foo ]
|> List.filter (is Foo)
// In fact, you can use the built-in equality test operator
[ Foo; Bar; Foo ] |> List.filter ((=) Foo)
この最後の方法は、場合によってはパラメーターを持つ、より複雑な識別された共用体がある場合は機能しないため、おそらくあまり役に立ちません。たとえば、オプション値のリストがある場合:
let opts = [ Some(42); None; Some(32) ]
opts |> List.filter (is Some) // ERROR - because here you give 'is' a constructor
// 'Some' instead of a value that can be compared.
Reflectionを使用して(指定された名前のケースをチェックするために)さまざまなトリックを実行できます。また、F#引用符を使用して、より適切で安全な構文を取得することもできますが、を使用してパターンマッチングを使用すると、function
かなりの価値があるとは思いません。明確なコード。
編集-好奇心から、リフレクションを使用するソリューション(そして、低速で、タイプセーフではなく、実際に何をしているのかを本当に理解していない限り、実際に使用するべきではありません)は次のようになります。
open Microsoft.FSharp.Reflection
open Microsoft.FSharp.Quotations
let is (q:Expr) value =
match q with
| Patterns.Lambda(_, Patterns.NewUnionCase(case, _))
| Patterns.NewUnionCase(case, _) ->
let actualCase, _ = FSharpValue.GetUnionFields(value, value.GetType())
actualCase = case
| _ -> failwith "Wrong argument"
引用符を使用してユニオンケースを識別するため、次のように記述できます。
type Case = Foo of int | Bar of string | Zoo
[ Foo 42; Zoo; Bar "hi"; Foo 32; Zoo ]
|> List.filter (is <@ Foo @>)