2013-08-19 63 views
3

我想域作爲記錄和識別聯合,即不可變模型的關係。我注意到,我有一個m:n的關係,比如作者和書籍。而現在我正在尋找表達它的一個很好的方式,使得:如何表達在F#

  • 理想不變
  • 一本書改變一個屬性是很容易,那就是,如果我想創建一個副本,我不不必遍歷所有作者
  • 訪問很簡單;理想情況下作者有書籍清單

到目前爲止,我沒有找到任何解決方案實現所有的標準。我發現的是:

  • 每個作者都有一個書目清單(我並不需要相反的方向)。這允許方便地訪問和是不可改變的,但是改變對一本書的性質需要改變每一個作者日期
  • 持有的書籍REF細胞的不可變列表,每個作者都有裁判細胞的不可變列表。這使得改變一個屬性容易,並且訪問很容易,但是這實際上並不是不可變的,因爲ref單元不是不可變的。
  • 持有的書籍不可變列表和每個作者有ID的不可變列表。這是不可改變的,並且對書籍進行更改變得簡單,但是訪問更加困難,因爲您需要執行查找,並且您可能有一個不存在的ID。

是否有任何解決方案可以滿足上述所有要求,或許像不可變的參考單元?如果是這樣,他們看起來像什麼。

+1

如果你做出'Book'可變的變化,能夠性質似乎簡單。任何理由不? – Daniel

+2

請注意,如果您有作者的不可變列表並將其映射到其上,則實際上並未最終複製所有作者。不改變的作者只是指向同一個實例(所以不可變解決方案的開銷並不大)。 –

+1

我不害怕運行時開銷,實際上,我更想知道如何以某種功能方式進行類似別名的操作。到目前爲止,我認爲讓它變得可變是最簡單的。問題是這樣的:假設你寫了3本書,每本書都是作爲你的作者,現在你改變了你的地址。我現在不得不在每本書中改變你的地址嗎?如果你是可變的,通過改變你的地址,我隱式更新所有書籍。但是,如何以功能性的方式實現相同的功能呢? –

回答

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可能更安全的選擇)。

+0

thx爲增加書的想法。在我們的例子中,我們真的只想編輯GUI中的細節,所以根本不涉及併發。 –