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

发布于 2024-12-16 17:28:30 字数 1082 浏览 0 评论 0原文

我希望 F# 对象表达式具有可变状态。 第一种方法是使用引用单元格,如下所示:

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 <- ret + 1 在性能关键部分)?我的猜测是 State 对象也分配在堆上,因此没有理由第二个版本应该更快。然而,它使用起来稍微更有吸引力。

感谢您的任何反馈和建议

I would like to have a mutable state in an F# object expression.
The first approach is to use ref cells as follows:

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

A different approach would be as follows:

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

Which version would be likely more performing (I need the state updating x.state <- ret + 1
in performance critical sections)? My guess is that the State object is also allocated on the heap so there is no reason why the second version should be faster. However it is slightly more appealing to use.

Thanks for any feedback and suggestions

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

樱娆 2024-12-23 17:28:30

正如 Daniel 所说,最后一种方法本质上等同于使用内置的 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)。

As Daniel said, the last approach is essentially equivalent to using built-in ref.

When using ref, you're allocating two objects - the one that you're returning and the reference cell itself. You can reduce this to just a single allocated object by using a concrete implementation (but I don't think this will matter in practice):

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

Aside, you are using read-only property that modifies internal state of the object and returns a new state each time. This is a dangerous pattern that could be quite confusing - properties with getter shouldn't modify the state, so you should probably use a method (unit -> int) instead.

执手闯天涯 2024-12-23 17:28:30

您的 State 类与 ref 相同。它们都是引用类型(您无法从对象表达式捕获可变值类型)。如果可能的话,我更喜欢内置类型。 ref 是表示堆分配的可变值的惯用方式。

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

Your State class is identical to ref. They're both reference types (you can't capture a mutable value type from an object expression). I would prefer a built-in type when possible. ref is the idiomatic way to represent a heap-allocated mutable value.

If ever in doubt about performance, benchmark it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文