2010-07-22 130 views
3

我有一個交易的單子,看起來像:交易類型安全

newtype Transaction t m a = .. my monad stack here ..

t是我使用,以確保我環比上升適用於同一後臺存儲的交易幻像類型。

我的主循環的迭代使用類型,如:

Transaction DB IO (Widget (Transaction DB IO()))

上述類型的意思是:「其生成UI窗口小部件,其用戶輸入轉換爲交易執行交易」。

此外,我有:

data Property m a = Property { get :: m a, set :: a -> m() }

這是非常有用的(特別是由於它與FCLabels撰寫能力

我做一個可怕的很多使用Property (Transaction t m)產生我的交易。

現在,我想要的類型系統,以保證生成的插件的事務是隻讀事務和交易Ť他的widget生成被允許爲讀寫事務。

顯然,我可以只添加另一個幻象類型的交易,但是這有兩個問題:

  • 它需要顯式轉換從Transaction ReadOnlyTransaction ReadWrite或類型級兩輪牛車允許之間的一元組成讀和寫基元。這我想我可以解決。

  • 屬性數據構造函數爲了包含寫入器,總是需要一個讀/寫操作來強制「m」成爲一個ReadWrite事務。我無法在讀寫和只讀事務的上下文中重新使用屬性。

我正在尋找一種獲得上述類型安全性的好方法,而不會丟失設計的上述特性。

+2

正如您指出的那樣,只要具有像'liftRORW :: Transaction ReadOnly t m a - > Transaction ReadWrite t m a'這樣的函數,用於跟蹤只讀/讀寫的幻像類型可以解決問題。這似乎是一個非常可靠的方法。 我不認爲我理解你提出的「財產」問題。 – intoverflow 2010-07-23 00:03:19

+0

改變幻像類型的轉換確實很重要,但只需要很少使用。大多數情況下,您可以創建一個函數,該函數可以是幻像類型中免費的ReadOnly或ReadWrite塊的一部分。 這是一個窮人的子類型。 – sclv 2010-07-23 01:09:51

+0

此外,您可以更改Property爲: 'data Property m a = Property {get :: forall free。 m free a,set :: a - > m ReadWrite()}' 雖然我不知道與那個和FCLabels互操作。 – sclv 2010-07-23 01:15:18

回答

3

如果您希望類型檢查器在只讀和讀寫事務之間實施區分,那麼這兩者必須是不同的類型。從那裏開始工作,該解決方案呈現爲:

data Property rm wm a = Property { get :: rm a, set :: a -> wm() } 

此方法有很多變體。相反,不同的單子,你可以有不同的上下文參數的單子:

newtype Transaction t c m a = .. my monad stack here 

data Property mc c1 c2 a = Property { get :: mc c1 a, set :: a -> mc c2() } 

這裏mc是一個單子的構造函數;它需要上下文參數來創建monad。儘管這使用了更多的參數,但我更喜歡它,因爲它強調了monads的相似性。

對於需要讀取或寫入的函數,請考慮使用類型類。

newtype ReadOnly = ReadOnly 

newtype ReadWrite = ReadWrite 

class ReadContext rm where 

class WriteContext rm where 

instance ReadContext ReadOnly where 
instance ReadContext ReadWrite where 

instance WriteContext ReadWrite where 

someGetter :: ReadContext c => Transaction t c m a 

someSetter :: WriteContext c => a -> Transaction t c m() 

這應該限制鑄件的量/解除你需要做的,同時還強制類型安全。

+0

偉大的想法,謝謝:-) – Peaker 2010-07-23 20:43:36