我有一个可以被歧视的联盟巧妙地描述的对象。它所代表的树具有一些属性,这些属性可以在修改树时轻松更新(但仍然是不可变的),但重新计算的成本相对较高。
我想将这些属性与对象一起存储为缓存值,但我不想将它们放入每个有区别的联合情况中,所以我认为一个成员变量适合这里。
问题是,如何在不改变实际对象的情况下更改成员值(当我修改树时)?我知道我可以修改树,然后在不破坏纯度的情况下改变该副本,但这对我来说似乎是错误的方式。如果有一些预定义的方法来更改属性,但操作的结果是一个新的对象,并且该属性发生了变化,那对我来说是有意义的。
澄清一下,当我说修改时,我的意思是以功能性方式进行修改。像(::)“追加”到列表的开头。我不确定这里有什么正确的术语。
答案 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)。
这允许记录类型是不可变的,并且保留大部分记录类型,而只更新一小部分。