F#对象表达式中的可变状态

时间:2011-11-17 16:26:47

标签: f# mutable ref

我想在F#对象表达式中有一个可变状态。 第一种方法是使用ref单元格如下:

type PP =
    abstract member A : int

let foo =
    let a = ref 0
    { new PP with
        member x.A = 
            let ret = !a
            a := !a + 1
            ret 
    }

printfn "%A" foo.A
printfn "%A" foo.A
printfn "%A" foo.A
printfn "%A" foo.A

另一种方法如下:

type State(s : int) =
    let mutable intState = s
    member x.state 
        with get () = intState
        and set v = intState <- v 

[<AbstractClass>]         
type PPP(state : State) =
    abstract member A : int
    member x.state 
        with get () = state.state
        and set v = state.state <- v 

let bar n =
    { new PPP(State(n)) with
        member x.A = 
            let ret = x.state
            x.state <- ret + 1
            ret  
    }

let barA1 = bar 0
printfn "%A" barA1.A
printfn "%A" barA1.A
printfn "%A" barA1.A
printfn "%A" barA1.A

哪个版本的性能可能更高(我需要更新状态x.state&lt; - ret + 1 在性能关键部分)?我的猜测是State对象也在堆上分配,所以没有理由为什么第二个版本应该更快。但是使用它会更有吸引力。

感谢您的任何反馈和建议

2 个答案:

答案 0 :(得分:5)

正如丹尼尔所说,最后一种方法基本上等同于使用内置ref

使用ref时,您要分配两个对象 - 您要返回的对象和参考单元本身。您可以通过使用具体实现将此减少为仅一个已分配的对象(但我认为这在实践中不重要):

type Stateful(initial:int) = 
  let mutable state = initial
  interface PP with
    member x.A =
      let ret = state
      state <- state + 1
      ret

let foo = 
   Statefull(0) :> PP // Creates a single object that keeps the state as mutable field

除此之外,您正在使用只读属性来修改对象的内部状态,并且每次都返回一个新状态。这是一个非常混乱的危险模式 - 带有getter的属性不应该修改状态,所以你应该使用方法(unit -> int)代替。

答案 1 :(得分:3)

您的State课程与ref相同。它们都是引用类型(您无法从对象表达式中捕获可变值类型)。我希望在可能的情况下使用内置类型。 ref是表示堆分配的可变值的惯用方法。

如果对性能有任何疑问,请对其进行基准测试。