[英]No instance for (Generic (f a)) arising from a use of `from'
I'm having issues with finding suitable type constraints for the following code 我遇到了为以下代码找到合适的类型约束的问题
{-# 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
It fails with 它失败了
No instance for (Generic (f a)) arising from a use of `from'
Adding the constraint to gname
like this 像这样将约束添加到
gname
instance (Generic (f a)) => GClass (f :+: g) where
fails with 失败了
Could not deduce (Generic (f a1)) arising from a use of `from'
from the context (Generic (f a))
Edit: The full error message for the full snippet 编辑:完整代码段的完整错误消息
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
This is with GHC 7.6.3 这是GHC 7.6.3
I presume you are trying to get the constructor names using Ghc.Generics
. 我假设您正在尝试使用
Ghc.Generics
获取构造函数名称。 Constructor, field, and data type metadata is held in M1
nodes. 构造函数,字段和数据类型元数据保存在
M1
节点中。 M1
nodes are tagged with either D
, C
, or S
to indicate whether they hold datatype, constructor, or selector (field) metadata. M1
节点标记有D
, C
或S
以指示它们是否包含数据类型,构造函数或选择器(字段)元数据。
I've simplified your Class
and GClass
to return the outermost constructor name instead of checking to see if it is a certain name. 我简化了你的
Class
和GClass
以返回最外层的构造函数名称,而不是检查它是否是某个名称。 I'm interpreting Class
as the class of types whose values have an outermost constructor with a name. 我正在将
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
We'd like to be able to derive a Class
instance for Value
and observe that cname One == "One"
and cname Two == "Two"
. 我们希望能够为
Value
派生一个Class
实例并观察cname One == "One"
和cname Two == "Two"
。
instance Class Value
main = do
print . cname $ One
print . cname $ Two
We need to implement GClass
for three of the representation nodes to be able to do this. 我们需要为三个表示节点实现
GClass
才能执行此操作。 The representation for One
is: One
的代表是:
> from One
M1 {unM1 = L1 (M1 {unM1 = U1})}
The outer M1
is an M1 D
holding in a dictionary the metadata for the Value
datatype. 外部
M1
是M1 D
,它在字典中保存Value
数据类型的元数据。 The L1
is selecting the first constructor, One
. L1
正在选择第一个构造函数One
。 The inner M1
is an M1 C
holding in a dictionary the metadata for the One
constructor. 内部
M1
是M1 C
,在字典中保存One
构造函数的元数据。 We don't care about anything deeper than it, since that M1
represents the outermost constructor. 我们并不关心比它更深的东西,因为
M1
代表最外层的构造函数。
The most interesting node is the inner M1 C
which holds the constructor metadata. 最有趣的节点是内部
M1 C
,它保存构造函数元数据。 We can get the constructor name as long as the metadata implements the Constructor
class. 只要元数据实现了
Constructor
类,我们就可以获得构造函数名称。 The Constructor
class includes conName
which returns the constructor name given an appropriate proxy, and the appropriate proxy type is designed to looks like the type of M1 C
. Constructor
类包含conName
,它在给定适当代理的情况下返回构造函数名称,并且相应的代理类型设计为看起来像M1 C
的类型。
conName :: Constructor c => t c (f :: * -> *) a -> [Char]
M1 C c f p
This means we can implement GClass
simply for M1 C
nodes as long as there's a Constructor
instance for the metadata tag c
这意味着只要有元数据标记
c
的Constructor
实例,我们就可以简单地为M1 C
节点实现GClass
instance (Constructor c) => GClass (M1 C c f) where
gname = conName
When we are faced with the choice between two constructors, :+:
, we can determine the outermost constructor name if we can determine the outermost constructor name of both constructors. 当我们面对两个构造函数之间的选择时,
:+:
:,如果我们可以确定两个构造函数的最外层构造函数名称,我们可以确定最外面的构造函数名称。
instance (GClass f, GClass g) => GClass (f :+: g) where
gname (L1 x) = gname x
gname (R1 x) = gname x
When we are dealing with a metadata node for a datatype, M1 D
, we can determine the outermost constructor name when we can determine the outermost constructor name of the representation absent the metadata node. 当我们处理数据类型
M1 D
的元数据节点时,我们可以在确定没有元数据节点的表示的最外层构造函数名称时确定最外层的构造函数名称。
instance GClass f => GClass (M1 D c f) where
gname (M1 x) = gname x
With these three instances we can run our desired code and see that 通过这三个实例,我们可以运行我们想要的代码并查看它
> cname One
"One"
> cname Two
"Two"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.