matchのネストを減らす小ネタ
まれに判別共用体の値がどのケースか分かっていることがある。 一般論としてはケースが絞り込まれる場所であらかじめケースを剥がしておくほうがよい。
しかしどうしても剥がしたいことはある。 その場合はmatchを使い、その他のパターンを例外送出でごまかす。
type MyValue =
    | Int of int
    | String of string
let onInt (value: MyValue) =
    match value with
    | Int n ->
        doSomething n
    | _ -> failwith "unreachable"
この状況で使える小ネタとして、以下のヘルパーを用意しておくと記述量が減る:
let inline private (|Unreachable|) (_: 'T) : 'U = failwith "unreachable"
let onInt (value: MyValue) =
    let (Int n | Unreachable n) = value
    doSomething n
ここで Unreachable というアクティブパターンを定義している。
必ずマッチに成功するので、let の左辺で使っても「パターンが網羅的でない」という警告が出ない。
実行時の挙動は前述の match と同じ。
Appendix. サンプルコード
/// Diverging active pattern.
let inline private (|Unreachable|) (_: 'T) : 'U = failwith "unreachable"
type MyValue =
    | Int of int
    | String of string
let doSomething (n: int) = printfn "int -> %d" n
// ----------
// match
// ----------
printfn "use match:"
let onInt1 (value: MyValue) =
    match value with
    | Int n ->
        doSomething n
    | _ -> failwith "unreachable"
onInt1 (Int 1) //=> int -> 1
try
    onInt1 (String "")
    assert false
with _ -> printfn "string -> raised"
// ----------
// let
// ----------
printfn "use let:"
let onInt2 (value: MyValue) =
    let (Int n | Unreachable n) = value
    doSomething n
onInt2 (Int 2) //=> int -> 2
try
    onInt2 (String "")
    assert false
with _ -> printfn "string -> raised"