![](/img/trans.png)
[英]How to provide an overlapping typeclass instance for an instantiation of a generic instance?
[英]Typeclass instance not found for generic
我不能讓GHC解決通用類型類的實例如下:(我們的目標是達到相同的效果訪問屬性x
的point
狀x point
,而且,由於不是利用類型級別的字符串)
data Label (l :: Symbol) =
Get
class Has a l b | a l -> b where
get :: a -> Label l -> b
instance (Generic r, GenericHas (Rep r) pl pt) => Has r pl pt where
get = genericHas . from
class GenericHas a l b | a l -> b where
genericHas :: a x -> Label l -> b
instance GenericHas (D1 a (C1 b (S1 (c ('Just pl) d e f) (Rec0 pt)))) pl pt where
genericHas (M1 (M1 (M1 (K1 v)))) _ = v
data Point =
Point
{ x :: Int
}
deriving (Show, Generic)
example :: Int
example = get (Point 1) (Get :: Label "x")
以下是錯誤:
* No instance for (GenericHas (D1 ('MetaData "Point" "Alba.Persistence" "alba-0.1.0.0-w6KgEimatKAP1g0rWS7YT" 'False) (C1 ('MetaCons "Point" 'PrefixI 'True) (S1 ('MetaSel ('Just "x") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int)))) "x" Int) arising from a use of `get' * In the expression: get (Point 1) (Get :: Label "x") In an equation for `example': example = get (Point 1) (Get :: Label "x")
問題是GHC無法將c
與'MetaSel
匹配,因為'MetaSel
是更高級別的。 默認情況下,假設新類型變量具有種類*
,因此匹配在此處失敗。
解決這個問題的一種方法是用'MetaSel
替換c
:
instance GenericHas (D1 a (C1 b (S1 (`MetaSel ('Just pl) d e f) (Rec0 pt)))) pl pt where
另一種方法是啟用PolyKinds
。 這將告訴GHC 不要對新變量采取類型*
,匹配將成功。
額外獎勵:您可以使用TypeApplications
獲得更好的語法。 您可以編寫Get @"x"
而不是Get :: Label "x"
。 或者你可以更進一步,定義一個包裝Get
的函數:
get' :: forall (l :: Symbol) a b. Has a l b => a -> b
get' a = get a (Get @l)
-- Usage:
example = get' @"x" (Point 1)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.