f# - 如何表达不变性保证

标签 f#

下面的代码显示了一些记录正在被具有相同签名(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/

相关文章:

f# - 如何使用 vscode 在 F# 项目中强制文件排序?

f# - 什么时候使用F#的typedefof <'T>与typeof <'T>?

d3.js - 将 D3 与 websharper 一起使用

Azure 存储类型提供程序 : FS0039 on build but intellisense shows type as available

f# - fsharp 中的自定义比较和相等

list - F# If 语句 List.exists

f# - 'T and ' U 在 F# 中是什么意思?

f# - F# 中的类型推断

c# - 是否可以通过 F# 创建第三方可变结构 "more immutable"?

python - 有没有办法控制 Apache Arrow 批量大小?