没有因使用“from”而产生的 (Generic (f a)) 实例
No instance for (Generic (f a)) arising from a use of `from'
我在为以下代码寻找合适的类型约束时遇到问题
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
import GHC.Generics
data Value = One | Two deriving Generic
class Class a where
cname :: a -> String -> Bool
default cname :: (Generic a, GClass (Rep a))
=> a -> String -> Bool
cname = gname . from
class GClass f where
gname :: f a -> String -> Bool
instance GClass (f :+: g) where
gname (L1 x) s | conName (from x) == s = True
| otherwise = False
gname (R1 x) s | conName (from x) == s = True
| otherwise = False
它失败了
No instance for (Generic (f a)) arising from a use of `from'
像这样将约束添加到 gname
instance (Generic (f a)) => GClass (f :+: g) where
失败
Could not deduce (Generic (f a1)) arising from a use of `from'
from the context (Generic (f a))
编辑:完整代码段的完整错误消息
Generic.hs:19:31:
No instance for (Generic (f a)) arising from a use of `from'
Possible fix: add an instance declaration for (Generic (f a))
In the first argument of `conName', namely `(from x)'
In the first argument of `(==)', namely `conName (from x)'
In the expression: conName (from x) == s
Generic.hs:21:31:
No instance for (Generic (g a)) arising from a use of `from'
Possible fix: add an instance declaration for (Generic (g a))
In the first argument of `conName', namely `(from x)'
In the first argument of `(==)', namely `conName (from x)'
In the expression: conName (from x) == s
这是 GHC 7.6.3
我假设您正在尝试使用 Ghc.Generics
获取构造函数名称。构造函数、字段和数据类型元数据保存在 M1
个节点中。 M1
节点标有 D
、C
或 S
以指示它们是否包含数据类型、构造函数或选择器(字段)元数据。
我已经将你的 Class
和 GClass
简化为 return 最外层的构造函数名称,而不是检查它是否是某个名称。我将 Class
解释为 class 类型,其值具有带名称的最外层构造函数。
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
import GHC.Generics
data Value = One | Two deriving Generic
class Class a where
cname :: a -> String
default cname :: (Generic a, GClass (Rep a))
=> a -> String
cname = gname . from
class GClass f where
gname :: f a -> String
我们希望能够为 Value
导出一个 Class
实例并观察 cname One == "One"
和 cname Two == "Two"
。
instance Class Value
main = do
print . cname $ One
print . cname $ Two
我们需要为三个表示节点实现 GClass
才能做到这一点。 One
的表示是:
> from One
M1 {unM1 = L1 (M1 {unM1 = U1})}
外层 M1
是一个 M1 D
在字典中保存 Value
数据类型的元数据。 L1
正在选择第一个构造函数,One
。内部 M1
是一个 M1 C
在字典中保存 One
构造函数的元数据。我们不关心比它更深的东西,因为 M1
代表最外层的构造函数。
最有趣的节点是包含构造函数元数据的内部 M1 C
。只要元数据实现了Constructor
class,我们就可以得到构造函数名。 Constructor
class 包括 conName
,其中 return 是给定适当代理的构造函数名称,适当的代理类型设计为看起来像 M1 C
的类型.
conName :: Constructor c => t c (f :: * -> *) a -> [Char]
M1 C c f p
这意味着只要元数据标签 c
有一个 Constructor
实例,我们就可以简单地为 M1 C
节点实现 GClass
instance (Constructor c) => GClass (M1 C c f) where
gname = conName
当我们面临两个构造函数之间的选择时,:+:
,如果我们能确定两个构造函数的最外层构造函数名称,我们就可以确定最外层的构造函数名称。
instance (GClass f, GClass g) => GClass (f :+: g) where
gname (L1 x) = gname x
gname (R1 x) = gname x
当我们处理数据类型的元数据节点时,M1 D
,当我们可以确定没有元数据节点的表示的最外层构造函数名称时,我们可以确定最外层构造函数名称。
instance GClass f => GClass (M1 D c f) where
gname (M1 x) = gname x
通过这三个实例,我们可以 运行 我们想要的代码并看到
> cname One
"One"
> cname Two
"Two"
我在为以下代码寻找合适的类型约束时遇到问题
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
import GHC.Generics
data Value = One | Two deriving Generic
class Class a where
cname :: a -> String -> Bool
default cname :: (Generic a, GClass (Rep a))
=> a -> String -> Bool
cname = gname . from
class GClass f where
gname :: f a -> String -> Bool
instance GClass (f :+: g) where
gname (L1 x) s | conName (from x) == s = True
| otherwise = False
gname (R1 x) s | conName (from x) == s = True
| otherwise = False
它失败了
No instance for (Generic (f a)) arising from a use of `from'
像这样将约束添加到 gname
instance (Generic (f a)) => GClass (f :+: g) where
失败
Could not deduce (Generic (f a1)) arising from a use of `from'
from the context (Generic (f a))
编辑:完整代码段的完整错误消息
Generic.hs:19:31:
No instance for (Generic (f a)) arising from a use of `from'
Possible fix: add an instance declaration for (Generic (f a))
In the first argument of `conName', namely `(from x)'
In the first argument of `(==)', namely `conName (from x)'
In the expression: conName (from x) == s
Generic.hs:21:31:
No instance for (Generic (g a)) arising from a use of `from'
Possible fix: add an instance declaration for (Generic (g a))
In the first argument of `conName', namely `(from x)'
In the first argument of `(==)', namely `conName (from x)'
In the expression: conName (from x) == s
这是 GHC 7.6.3
我假设您正在尝试使用 Ghc.Generics
获取构造函数名称。构造函数、字段和数据类型元数据保存在 M1
个节点中。 M1
节点标有 D
、C
或 S
以指示它们是否包含数据类型、构造函数或选择器(字段)元数据。
我已经将你的 Class
和 GClass
简化为 return 最外层的构造函数名称,而不是检查它是否是某个名称。我将 Class
解释为 class 类型,其值具有带名称的最外层构造函数。
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
import GHC.Generics
data Value = One | Two deriving Generic
class Class a where
cname :: a -> String
default cname :: (Generic a, GClass (Rep a))
=> a -> String
cname = gname . from
class GClass f where
gname :: f a -> String
我们希望能够为 Value
导出一个 Class
实例并观察 cname One == "One"
和 cname Two == "Two"
。
instance Class Value
main = do
print . cname $ One
print . cname $ Two
我们需要为三个表示节点实现 GClass
才能做到这一点。 One
的表示是:
> from One
M1 {unM1 = L1 (M1 {unM1 = U1})}
外层 M1
是一个 M1 D
在字典中保存 Value
数据类型的元数据。 L1
正在选择第一个构造函数,One
。内部 M1
是一个 M1 C
在字典中保存 One
构造函数的元数据。我们不关心比它更深的东西,因为 M1
代表最外层的构造函数。
最有趣的节点是包含构造函数元数据的内部 M1 C
。只要元数据实现了Constructor
class,我们就可以得到构造函数名。 Constructor
class 包括 conName
,其中 return 是给定适当代理的构造函数名称,适当的代理类型设计为看起来像 M1 C
的类型.
conName :: Constructor c => t c (f :: * -> *) a -> [Char]
M1 C c f p
这意味着只要元数据标签 c
Constructor
实例,我们就可以简单地为 M1 C
节点实现 GClass
instance (Constructor c) => GClass (M1 C c f) where
gname = conName
当我们面临两个构造函数之间的选择时,:+:
,如果我们能确定两个构造函数的最外层构造函数名称,我们就可以确定最外层的构造函数名称。
instance (GClass f, GClass g) => GClass (f :+: g) where
gname (L1 x) = gname x
gname (R1 x) = gname x
当我们处理数据类型的元数据节点时,M1 D
,当我们可以确定没有元数据节点的表示的最外层构造函数名称时,我们可以确定最外层构造函数名称。
instance GClass f => GClass (M1 D c f) where
gname (M1 x) = gname x
通过这三个实例,我们可以 运行 我们想要的代码并看到
> cname One
"One"
> cname Two
"Two"