reference - 如何在 F# 中表达关系

标签 reference f# entity immutability ref

我正在尝试将域建模为记录和可区分的联合,即不可变的。我注意到,我有一个 m:n 关系,比如作者和书籍。现在我正在寻找一种表达它的好方法,例如:

  • 最好是不可变的
  • 更改一本书的属性很容易,也就是说,如果我想创建一个副本,我不必遍历所有作者
  • 访问简单;理想情况下,作者有一个书单

到目前为止,我没有找到满足所有标准的解决方案。我发现的是:

  • 每个作者都有一个书单(我真的不需要相反的方向)。这允许轻松访问并且是不可变的,但是更改一本书的属性需要更改每个作者
  • 拥有一个不可变的书籍引用单元列表,每个作者都有一个不可变的引用单元列表。这使得更改属性和访问变得容易,但这实际上并不是不可变的,因为引用单元格不是不可变的。
  • 拥有一个不可变的图书列表,每个作者都有一个不可变的 ID 列表。这是不可变的,可以轻松更改书籍,但访问起来比较困难,因为您需要进行查找并且您可能拥有不存在的 ID。

是否有任何解决方案可以满足上述所有条件,比如不可变的引用单元?如果是这样,它们看起来像什么。

最佳答案

正如我在评论中提到的,如果您有一个不可变的作者列表并对其进行映射,您实际上并不会最终复制所有作者。不改变的作者只会指向同一个实例(所以不可变解决方案的开销不是那么大)。

但是,如果您有多本同一作者的书,则不会出现别名,因此作者都是不同的值(并且您必须映射所有书)。

我认为在这种情况下合理的表示是将作者和书籍分开并通过键(例如作者姓名 - 在下面的示例中 - 或其他一些 ID)将它们链接起来:

type Author = { Name : string; Address : string }
type Book = { Title : string; Author : string }

// For efficient lookup, create a hashtable with authors 
let authors = dict [ "Tomas", { Name = "Tomas"; Address = "Cambridge" } ]
// Books are stored simply as a list
let books = [ { Title = "Real World FP"; Author = "Tomas" } ]

// To get nice access, add AuthorDetails property to the Author record
type Book with 
  member x.AuthorDetails = authors.[x.Author]

for book in books do 
  printfn "%s (%s, %s)" book.Title book.Author book.AuthorDetails.Address

这不会让您改变集合 authors。如果您以纯函数式方式编写此代码,您可能会有一些递归函数将当前作者作为参数,因此您不需要修改(只需构建一个新字典)。

但我认为用一个 ref 值来保存字典是合理的,或者甚至保留一个可变字典(但我只会在没有并发的情况下这样做;事实上,存在的并发性,Map 可能是更安全的选择)。

关于reference - 如何在 F# 中表达关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18318150/

相关文章:

c++ - C++对对象的引用类似于C中的双指针吗?

types - 为什么不能为嵌套函数推断类型

java - (解决方法)在实体上使用@ConditionalOnProperty

Java 架构 3 层对象设计

php - 交响乐 : can't we have a hidden entity field?

outlook - MS 访问引用

c++ - 从(std::function)输出lambda中的引用传递值?

javascript - 关于javascript函数引用的问题

.net - Regex.CompileToAssembly 如何设置.dll 文件位置

f# - 如何使用被覆盖的抽象成员的基本实现?