下面的代码显示了一些记录正在被具有相同签名(RwA -> RwA
)的 2 个函数处理的情况。然而,根据该更改器函数的实现,传递给它的数据可能会更改,也可能不会更改。
在更大的项目中,这样的事情可能代价高昂。也许在维护或优化期间,更改了功能的实现或添加了更多更改功能,程序看起来还是一样,但突然出现了意想不到的行为。
所以问题是:有没有什么方法可以呈现此示例中的代码,很明显(并且编译器已检查)RwAChanger
类型的函数可能会或可能不会更改它作为参数传递的数据?
请不要回复“不要使用数组”,因为这可能是大量数据,例如 3D 网格的顶点或类似的数据,其中性能会成为问题。 此外,我确信可以找到其他示例,这些示例不涉及会产生相同类型问题的数组。
// A record with arrays...
type RwA =
{
A : int array
I : int array
}
let x = [| for i in 0..10 -> i |]
let init a =
{ A = a; I = Array.map (fun v -> -v ) a }
// This function creates a new array as member A in RwA
let change (o : RwA) : RwA =
{ o with A = Array.map (fun v -> v + 42) o.A }
// This function modifies the value of the array in member A of an RwA instance.
let change2 (o: RwA) : RwA =
o.A.[0] <- 666
o
let dump (o : RwA) =
printfn "{ A = %A; I = %A; }" o.A o.I
o
let dumpA (a : int array) : int array =
printfn "x = %A" x
a
// Is there a way to express a contract about immutability?
type RwAChanger = RwA -> RwA
let transmogrify (changer : RwAChanger) a =
a
|> dumpA
|> init
|> dump
|> changer
|> dump
|> ignore
let test() =
transmogrify change x
dumpA x |> ignore
transmogrify change2 x
dumpA x |> ignore
do test()
最佳答案
我认为没有办法告诉编译器应该将现有的可变类型设置为不可变类型,也没有办法像@mydogisbox 在评论中提到的那样使用代码契约。
但是您可以使用 ImmutableArray<T>
来自 Microsoft.Bcl.Immutable
包裹在你的RwA
记录。数组访问的性能差异应该很小。
关于f# - 如何表达不变性保证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25688825/