[英]Value in typeclass without type variable constraint
我正在使用Happstack開發Webapp,正在編寫一些代碼將類型存儲在MongoDB中。 我想通過將代碼放入類型類中來縮短代碼,以便可以使用相同的代碼針對不同類型對數據庫進行讀寫。 像這樣:
class DatabaseType a where
toDoc :: a -> Document
fromDoc :: Document -> a
saveCollection :: Text
getFromDatabase :: (MonadIO m) => Pipe -> Text -> Value -> m a
getFromDatabase pipe field value = ...
...
現在的問題是saveCollection
,因為它不使用GHC不會編譯的任何類型變量,但是對數據庫函數(如getFromDatabase
)來說非常重要,這樣它們才知道要保存到哪個集合。
問題是,如何在類型類中具有不受類型變量約束的值。
您必須添加類型變量。 最簡單的方法是使用代理:
saveCollection :: proxy a -> Text
-- Note the `proxy` is lower case
instance DatabaseType MyDB where
saveCollection _ = "MyDB"
現在使用它,您可能會這樣做:
import Data.Proxy
foo = saveCollection (Proxy :: Proxy MyDB)
在方法聲明中使用小寫字母的原因是方便:如果您恰巧在調用站點有一個值,則可以使用類型具有正確格式的任何值來代替Proxy MyDB
。
在某些情況下,標准代理技術可能會導致共享丟失。 發生這種情況是因為通常不會記住函數調用的結果。 在這種情況下,可以使用標記類型。 Data.Tagged
定義
newtype Tagged s b = Tagged {unTagged :: b}
標記類型比代理更難使用,除非您使用GHC最近添加的兩個功能部分類型簽名或顯式類型應用程序。 不過,如果您願意,可以寫
saveCollection :: Tagged a Text
然后在實例中
saveCollection = Tagged "Hi there."
直接使用它需要類似
unTagged (saveCollection :: Tagged MyDB Text)
或者,使用部分類型簽名,
unTagged (saveCollection :: Tagged MyDB _)
或使用顯式類型應用程序, 我認為類似
unTagged (saveCollection@MyDB)
由於這種尷尬,帶tagged
軟件包提供了在基於代理的表示和帶標記的表示之間進行轉換的功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.