F# プログラマーの初心者にとって一般的な驚きは、以下が不完全な一致であるという事実です。
let x, y = 5, 10
match something with
| _ when x < y -> "Less than"
| _ when x = y -> "Equal"
| _ when x > y -> "Greater than"
しかし、私は驚くべき状況に遭遇しました。これを示すための小さなサンプル コードを次に示します。
type Tree =
| Leaf of int
| Branch of Tree list
let sapling = Branch [Leaf 1] // Small tree with one leaf
let twoLeafTree = Branch [Leaf 1; Leaf 2]
let describe saplingsGetSpecialTreatment tree =
match tree with
| Leaf n
| Branch [Leaf n] when saplingsGetSpecialTreatment ->
sprintf "Either a leaf or a sapling containing %d" n
| Branch subTree ->
sprintf "Normal tree with sub-tree %A" subTree
describe true sapling // Result: "Either a leaf or a sapling containing 1"
describe false sapling // Result: "Normal tree with sub-tree [Leaf 1]"
describe true twoLeafTree // Result: "Normal tree with sub-tree [Leaf 1; Leaf 2]"
describe false twoLeafTree // Result: "Normal tree with sub-tree [Leaf 1; Leaf 2]"
このバージョンのdescribe
関数は、パターン マッチが実際には完全であるにもかかわらず、「この式のパターン マッチが不完全です」という警告を生成しました。そのパターン マッチに一致しない可能性のあるツリーはありません。これは、式を含むマッチの特定のブランチを削除することで確認できます。when
let describe tree =
match tree with
| Leaf n -> sprintf "Leaf containing %d" n
| Branch subTree ->
sprintf "Normal tree with sub-tree %A" subTree
このバージョンのは、とツリーdescribe
の両方に対して「通常のツリー」文字列を返します。sapling
twoLeafTree
match
式に式しか含まれていない場合(とが比較されているwhen
最初の例のように)、F# コンパイラが一致が完全かどうかを判断できない可能性があるのは当然です。結局のところ、これら 3 つの分岐のいずれも真ではない比較と等価の「奇妙な」実装を持つ型である可能性があります。x
y
x
y
しかし、私のdescribe
関数のような場合、なぜ F# コンパイラはパターンを調べず、「すべてのwhen
式が に評価された場合false
でも、完全な一致が存在する」と言って、「不完全なパターン一致」の警告をスキップしないのですか? この警告がここに表示される特定の理由がありますか? それとも、コードが十分に洗練されていないために、F# コンパイラがここで少し単純化され、誤検知の警告を出すだけの場合ですか?
* 実際、標準の .Net 型システムの「通常の」境界を超えることなく、 、、およびがすべてfalse になるような値をx
およびに設定することができます。おまけの質問/パズルとして、とのこれらの値は何ですか? このパズルに答えるのにカスタム型は必要ありません。必要なのは、標準の .Net で提供される型だけです。y
x < y
x = y
x > y
x
y