如何使F#只执行一次方法?

时间:2012-03-11 18:16:29

标签: f#

我想定义一个类型:

type blah =
     AThing
   | AnotherThing
   with 
     static member ofString : string -> blah
     override x.ToString () : string

我想确保这两种方法始终保证一致。这样做的一个好方法是从同一个对列表中构造两个映射,然后将它们转换为两个方法的明显实现。大致是:

let pairs = [Athing, "AThing"; AnotherThing, "AnotherThing"]
let tostr = Map.ofList pairs
let toblah = pairs |> List.map swap |> Map.ofList

我认为这段代码只能在静态成员函数中定义。需要可以从ofString访问静态位,这是静态的。它不能在类型之前定义,因为列表依赖于它。之后无法定义,因为F#不允许稍后声明和实现方法(以与C ++相同的方式)。这样就可以在静态成员和静态成员之间进行选择。编译器说扩充中不允许使用static let。 (?)

当放入静态成员函数时,代码工作正常,但是每次需要它时都会生成映射。不用说,这甚至比线性搜索效率更低。我该怎么做呢?非常感谢。

4 个答案:

答案 0 :(得分:3)

编译(带警告)

type blah = 
     AThing 
   | AnotherThing 

let pairs = [AThing, "AThing"; AnotherThing, "AnotherThing"] 
let tostr = Map.ofList pairs 
let toblah = pairs |> List.map (fun (x,y)->y,x) |> Map.ofList 

type blah
   with  
     static member ofString s = toblah.[s]
     override x.ToString () = tostr.[x]

并演示扩充(定义类型,执行其他代码,然后执行type blah with以定义更多成员)。

答案 1 :(得分:2)

我不明白你的观点。出了什么问题:

type blah =
   | AThing
   | AnotherThing
   with 
     static member ofString = function
            | "AThing" -> AThing
            | "AnotherThing" -> AnotherThing
            | _ -> failwith "Unwellformed string"

     override x.ToString () =
            match x with
            | AThing -> "AThing"
            | AnotherThing -> "AnotherThing"

模式匹配是Θ(1),它在F#中非常有效。

答案 2 :(得分:2)

我相信你正在努力做到以下几点:因为任何被歧视的联盟都有能力从特定的DU情况转变为其名称并且没有负担硬编码每对的关系,这两个答案都由Brian和垫。

如果牺牲ToString()的覆盖来代替等效的静态成员,可以使用以下方法完成:

open Microsoft.FSharp.Reflection
type Blah =
    | AThing
    | AnotherThing

[<AutoOpenAttribute>]
module BlahExt =
    let cases = FSharpType.GetUnionCases typeof<Blah>
    let toBlah = dict [for case in cases do yield (case.Name, FSharpValue.MakeUnion(case, [||]) :?> Blah)]
    let fromBlah = dict [for case in cases do yield ((FSharpValue.MakeUnion(case, [||]) :?> Blah), case.Name)]
    type Blah     
    with
        static member ofString name =
            if toBlah.ContainsKey name then (toBlah.Item name) else failwith "bad string"
        static member toString x = fromBlah.Item x

现在printfn "ofString: %A" (Blah.ofString "AThing")显示工会案例AThing,反之亦然printfn "toString: %s" (Blah.toString AThing)显示字符串AThing

您可以注意到我没有列出您的DU的成员,这通过反射实现,并保证自动正确映射。对于任意数量的单位情况,这种方法 - 两两百个 - 无需对特定情况进行硬编码。

答案 3 :(得分:2)

以下是根据需要运行的代码:

type blahFactory() =
    static let pairs = printf "array initialized; "; [AThing, "AThing"; AnotherThing, "AnotherThing"]
    static member tostr = Map.ofList pairs
    static member toblah = pairs |> List.map swap |> Map.ofList
and blah =
    | AThing
    | AnotherThing
    with
    static member ofString (string) = blahFactory.toblah.[string]
    override x.ToString () = blahFactory.tostr.[x]

我已经放置printf指令来演示数组只被初始化一次。

您可能认为有用的几点想法 首先,使用DU是提供样本的开销。如果您的数据很简单,您可以考虑使用enum类型 如果你真的是指DU,这可能是未来可能出现问题的迹象。考虑一下:

type blah =
    | AThing of string
    | AnotherThing of int * int

在这种情况下,构造和比较都是不可能的。

您有任何理由不使用标准XML序列化吗?