找不到泛型的类型类实例
Typeclass instance not found for generic
我无法让 GHC 解析下面的通用类型类实例:(目标是实现与访问 point
的 属性 x
相同的效果,例如 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
属于更高一类。默认情况下,假定新类型变量具有种类 *
,因此此处匹配失败。
解决此问题的一种方法是将 c
替换为 'MetaSel
:
instance GenericHas (D1 a (C1 b (S1 (`MetaSel ('Just pl) d e f) (Rec0 pt)))) pl pt where
另一种方法是启用PolyKinds
。这将告诉 GHC not 假设新变量的种类 *
并且匹配将成功。
好处: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)
我无法让 GHC 解析下面的通用类型类实例:(目标是实现与访问 point
的 属性 x
相同的效果,例如 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
属于更高一类。默认情况下,假定新类型变量具有种类 *
,因此此处匹配失败。
解决此问题的一种方法是将 c
替换为 'MetaSel
:
instance GenericHas (D1 a (C1 b (S1 (`MetaSel ('Just pl) d e f) (Rec0 pt)))) pl pt where
另一种方法是启用PolyKinds
。这将告诉 GHC not 假设新变量的种类 *
并且匹配将成功。
好处: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)