简体   繁体   English

使用“from”时没有(Generic(fa))的实例

[英]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节点标记有DCS以指示它们是否包含数据类型,构造函数或选择器(字段)元数据。

I've simplified your Class and GClass to return the outermost constructor name instead of checking to see if it is a certain name. 我简化了你的ClassGClass以返回最外层的构造函数名称,而不是检查它是否是某个名称。 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. 外部M1M1 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. 内部M1M1 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 这意味着只要有元数据标记cConstructor实例,我们就可以简单地为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM