所以我有一個有點像這樣的型別
class Stringify x where
stringify :: x -> String
我還有另外兩個類似的型別類
class LTextify x where
ltextify :: x -> L.Text
class Textify x where
textify :: x -> T.Text
我想定義依賴型別類
class (LTextify x) => Stringify x where
stringify = L.unpack . ltextify
class (Textify x) => Stringify x where
stringify = T.unpack . textify
但當然,haskell 抱怨“重復的實體宣告”,這當然是真的。我試過玩 OVERLAPPABLE 和 OVERLAPPING,但無濟于事。我想要的是,如果一個類有一個 LTextify 的實體,那么應該使用它。如果沒有,那么如果它有一個 Textify 實體,那么應該使用它來實作 Stringify。而且我希望一個類也能夠顯式地為 Stringify 定義一個實體,然后該實體與可能存在的 Textify 或 LTextify 實體重疊。當然是確定性的。
uj5u.com熱心網友回復:
我假設最后兩個應該是實體宣告而不是類宣告?
instance (LTextify x) => Stringify x where ...
instance (Textify x) => Stringify x where ...
根據 Haskell 中是否存在或不真正支持實體具有不同的行為,因為孤立實體意味著可用實體的串列可能會根據匯入以不可預測的方式發生變化。我建議(如果可能的話)改為創建一個和Stringify的超類。TextifyLTextify
此外,這些特定實體是不可能生成的,因為 GHC 實體決議的第一步是丟棄所有約束并檢查哪個實體在結構上匹配,所以它看起來像這樣:
instance Stringify x
instance Stringify x
根本無法區分這兩者,因此 ghc 將不得不在其中一個之間任意選擇,并希望它是正確的。
為了使用OVERLAPPING編譯指示,需要有一個比另一個更具體的實體,比如
instance C a => Foo [a]
instance {-# OVERLAPPING #-} Foo [Char]
有關其作業原理的更深入說明,請參閱用戶手冊中的此部分。這是一個相關的報價:
GHC 要求使用哪個實體宣告來解決型別類約束是明確的。GHC 還提供了一種放寬實體決議的方法,只要有一個最具體的實體,就允許匹配多個實體。
還有一個不推薦使用的擴展IncoherentInstances,它允許多個匹配實體,即使一個不嚴格比另一個更具體,但甚至不能在這里使用,因為兩個實體在結構上是相同的。
IncoherentInstances將任意選擇其中一個實體,因此應盡可能避免使用它,并且僅在匹配哪個實體無關緊要時才使用它。
編輯:在定義實體時減少樣板檔案的一種方法是與新DerivingVia型別包裝器一起使用:
newtype UsingLTextify a = UsingLTextify { unwrapLT :: a }
newtype UsingTextify a = UsingTextify { unwrapT :: a }
instance LTextify a => Stringify (UsingLTextify a) where
stringify = L.unpack . ltextify . unwrapLT
instance Textify a => Stringify (UsingTextify a) where
stringify = T.unpack . textify . unwrapT
然后你可以用它來派生這樣的實體
{-# LANGUAGE DerivingVia #-}
data Foo = ...
deriving Stringify via UsingLTextify Foo
instance LTextify Foo where ...
如果您無法控制資料型別并且不想添加孤立實體(如果可能,您應該避免這樣做),也可以直接使用這些新型別,方法是將它們包裝在您的資料周圍以提供相關實體。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/462820.html
標籤:哈斯克尔
