3

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

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

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

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

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

4

1 回答 1

4

正如我在评论中提到的,如果你有一个不可变的作者列表并在其上映射,你实际上并没有最终复制所有作者。不改变的作者将只是指向同一个实例(因此不可变解决方案的开销并不大)。

但是,如果您有多本同一作者的书籍,则确实没有别名,因此作者都是单独的值(并且您必须映射所有书籍)。

我认为在这种情况下,一个合理的表示是保持作者和书籍分开,并通过一个键(例如作者姓名 - 在下面的示例中 - 或其他一些 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可能是更安全的选择)。

于 2013-08-19T20:06:50.653 回答