对象上的不可变成员

时间:2014-07-05 08:04:11

标签: f#

我有一个可以被歧视的联盟巧妙地描述的对象。它所代表的树具有一些属性,这些属性可以在修改树时轻松更新(但仍然是不可变的),但重新计算的成本相对较高。

我想将这些属性与对象一起存储为缓存值,但我不想将它们放入每个有区别的联合情况中,所以我认为一个成员变量适合这里。

问题是,如何在不改变实际对象的情况下更改成员值(当我修改树时)?我知道我可以修改树,然后在不破坏纯度的情况下改变该副本,但这对我来说似乎是错误的方式。如果有一些预定义的方法来更改属性,但操作的结果是一个新的对象,并且该属性发生了变化,那对我来说是有意义的。

澄清一下,当我说修改时,我的意思是以功能性方式进行修改。像(::)“追加”到列表的开头。我不确定这里有什么正确的术语。

2 个答案:

答案 0 :(得分:2)

最简洁的方法就是以这种或那种方式携带附加到DU(作为案例的一部分)的“缓存”值。我可以想到几种方法来实现它,我只会给你一个,其中有缓存和非缓存模式的单独案例:

type Fraction =
    | Frac of int * int
    | CachedFrac of (int * int) * decimal
    member this.AsFrac =
        match this with
        | Frac _ -> this
        | CachedFrac (tup, _) -> Frac tup

一个完全不同的选择是将缓存的值保存在单独的字典中,如果你想要做的就是节省一些时间来重新计算它们,这是有意义的。

module FracCache = 
   let cache = System.Collections.Generic.Dictionary<Fraction, decimal>()

   let modify (oldFrac: Fraction) (newFrac: Fraction) =
       cache.[newFrac] <- cache.[oldFrac] + 1 // need to check if oldFrac has a cached value as well.

基本上,memoize会给你什么,而且你可以更好地控制它。

答案 1 :(得分:2)

F#实际上有复制和更新记录的语法。

语法如下:

let myRecord3 = { myRecord2 with Y = 100; Z = 2 }

(来自MSDN记录页面的示例 - http://msdn.microsoft.com/en-us/library/dd233184.aspx)。

这允许记录类型是不可变的,并且保留大部分记录类型,而只更新一小部分。

相关问题