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 回答