5

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の両方に対して「通常のツリー」文字列を返します。saplingtwoLeafTree

match式に式しか含まれていない場合(とが比較されているwhen最初の例のように)、F# コンパイラが一致が完全かどうかを判断できない可能性があるのは当然です。結局のところ、これら 3 つの分岐のいずれも真ではない比較と等価の「奇妙な」実装を持つ型である可能性があります。xyxy

しかし、私のdescribe関数のような場合、なぜ F# コンパイラはパターンを調べず、「すべてのwhen式が に評価された場合falseでも、完全な一致が存在する」と言って、「不完全なパターン一致」の警告をスキップしないのですか? この警告がここに表示される特定の理由がありますか? それとも、コードが十分に洗練されていないために、F# コンパイラがここで少し単純化され、誤検知の警告を出すだけの場合ですか?

* 実際、標準の .Net 型システムの「通常の」境界を超えることなく、 、、およびがすべてfalse になるような値をxおよびに設定することができます。おまけの質問/パズルとして、とのこれらの値は何ですか? このパズルに答えるのにカスタム型は必要ありません。必要なのは、標準の .Net で提供される型だけです。yx < yx = yx > yxy

4

2 に答える 2