3

F# で、任意の代数データ型の述語とアクセサーをタイプセーフな方法で自動的に生成することは可能ですか?

たとえば、ユーザー定義型がある場合:

type A = 
    B of string
    | C of int * sting

次のように生成する必要があります。

type A = 
    B of string
    | C of int * sting
    with
        member __.isB = match __ with B -> true | _ -> false
        member __.isC = match __ with C -> true | _ -> false
        member __._1 = match __ with B(x) -> Some(x) | _ -> None
        member __._2 = match __ with C(x,_) -> Some(x) | _ -> None
        member __._3 = match __ with C(_,x) -> Some(x) | _ -> None

アクセサーの名前を指定できる場合は、次のような注釈を付けることができます。

[<GenerateAccessors(["BName", "CName", "Value"])>]

内部データへのアクセスを簡単にしたい場合は、それができないか、判別共用体 (DU) の代わりにレコードを使用する必要があります。しかし、DU でパターン マッチングを使用する方が単純であり、単純なパターン マッチングと単純な「直接データ アクセス」の両方を同時に実現したいと考えています。

4

1 に答える 1

2

FSharpType.GetUnionCasesを使用して識別された共用体を反映し、F#PowerPackで使用可能なF#CodeDOMを使用するか、テキストを記述するだけでコードを生成できます。

open Microsoft.FSharp.Reflection

type A = B of string | C of int * string

let generate t =
    let cases = FSharpType.GetUnionCases(t)
    printfn "type %s with" t.Name
    for case in cases do
        printfn "\tmember value.is%s = " case.Name
        let fields = 
            match [for field in case.GetFields() -> "_"] with
            | [] -> ""
            | fields -> " (" + (fields |> String.concat ",") + ")"
        printfn "\t\tmatch value with %s%s -> true | _ -> false" case.Name fields

generate typeof<A>

F#タイプの拡張機能を生成します:

type A with
    member value.isB =
        match value with B (_) -> true | _ -> false
    member value.isC =
        match value with C (_,_) -> true | _ -> false
于 2013-03-10T16:38:49.007 に答える