我使用类型族重构了我的代码,下面是项目中使用的类型类。
class HeukaryaGene (d :: *) where
type TypeGeneStr d :: *
type TypeGeneRep d :: *
lexByArrow :: TypeGeneStr d -> [TypeGeneStr d]
geneTypeRep :: d -> TypeGeneRep d
geneTypeRepArgs :: TypeGeneRep d -> [TypeGeneRep d]
showGeneTypeRep :: TypeGeneRep d -> TypeGeneStr d
showExpandTypeArgs :: d -> [TypeGeneStr d]
showExpandTypeArgs dynam = lexByArrow typo
where
typo = showGeneTypeRep $ geneTypeRep dynam :: TypeGeneStr d但是ghc总是抱怨很多相同的事情:
Could not deduce (TypeGeneStr d ~ TypeGeneStr d2)
from the context (HeukaryaGene d)
bound by the class declaration for `HeukaryaGene'
at AI/Heukarya/Gene.hs:(22,1)-(42,63)
NB: `TypeGeneStr' is a type function, and may not be injective
The type variable `d2' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Expected type: [TypeGeneStr d]
Actual type: [TypeGeneStr d2]
In the return type of a call of `lexByArrow'
In the expression: lexByArrow typo
In an equation for `showExpandTypeArgs':
showExpandTypeArgs dynam
= lexByArrow typo
where
typo = showGeneTypeRep $ geneTypeRep dynam :: TypeGeneStr d我想知道我误解了什么
发布于 2013-07-21 01:31:22
您不能从TypeGeneStr d这样的类型族返回到原始类型d。当GHC说"NB:`TypeGeneStr'是一个类型函数,可能不是内射的“时,这就是它告诉你的:只要知道TypeGeneStr d ~ TypeGeneStr d'并不意味着d ~ d' (其中~是类型相等)。
因此,如果您的类型类函数的名称中只有类型同义词,并且从不引用原始参数,那么您将永远无法调用它-这将描述您的类型类中除geneTypeRep和无法实现的showExpandTypeArgs之外的所有函数。失败的原因是GHC不能确定使用类型类的哪个实例。考虑一下如果我允许TypeGeneStr和/或TypeGeneRep发生冲突会发生什么,如下例所示:
class HeukaryaGene Int where
type TypeGeneStr Int = String
type TypeGeneRep Int = ()
showGeneTypeRep () = "Int"
class HeukaryaGene Bool where
type TypeGeneStr Bool = String
type TypeGeneRep Bool = ()
showGeneTypeRep () = "Bool"那么showGeneTypeRep ()应该是"Int"还是"Bool"?或者它甚至应该是一个String?如果我有
class HeukaryaGene () where
type TypeGeneStr () = ()
type TypeGeneRep () = ()
showGeneTypeRep () = ()那么showGeneTypeRep ()也可以是()。这就是你对showExpandTypeArgs的定义:在typo内部,虽然GHC可以正确地确定dynam :: d,从而确定geneTypeRep dynam :: TypeGeneRep d,但它不知道应该选择哪个showGeneTypeRep :: TypeGeneRep d -> TypeGeneStr d。您对lexByArrow的调用遇到了类似的问题: GHC只知道某个d'的typo :: TypeGeneStr d',而它不知道选择哪个版本的lexByArrow :: TypeGeneStr d' -> [TypeGeneStr d'] (它确实知道TypeGeneRep d ~ TypeGeneRep d',但这不足以决定)。
在我的GHC (7.4.2)上,我也得到了一个错误,即Typo的类型签名中的d与类型类头中的d不同,但是删除该类型签名(显然)并不能得到类型检查的结果。
(我应该说:您在这里得到的错误消息肯定是令人困惑的,因为它们不清楚发生了什么以及为什么会出现错误。)
我能想到的最简单的解决方法是为所有不接受d参数的函数包含一个虚拟参数。您永远不会分析这个参数;它只是用来引导实例选择。在调用点,您可以对某些具体类型d使用undefined :: d。它看起来像这样:
class HeukaryaGene (d :: *) where
type TypeGeneStr d :: *
type TypeGeneRep d :: *
lexByArrow :: d -> TypeGeneStr d -> [TypeGeneStr d]
geneTypeRep :: d -> TypeGeneRep d
geneTypeRepArgs :: d -> TypeGeneRep d -> [TypeGeneRep d]
showGeneTypeRep :: d -> TypeGeneRep d -> TypeGeneStr d
showExpandTypeArgs :: d -> [TypeGeneStr d]
showExpandTypeArgs dynam = lexByArrow dynam typo
where
typo = showGeneTypeRep dynam $ geneTypeRep dynam如果你不喜欢这一点,我能想到的最小侵入性的修复方法是从类型族到数据族。数据族类似于类型族,只是您使用了关键字data,并且它们定义了全新的数据类型。这一点很重要:就像普通的数据结构一样,数据族是生成性的,因此是内射性的。(数据族的每个实例化都会生成一个全新的类型。)它看起来像这样:
class HeukaryaGene (d :: *) where
data TypeGeneStr d :: *
data TypeGeneRep d :: *
lexByArrow :: TypeGeneStr d -> [TypeGeneStr d]
geneTypeRep :: d -> TypeGeneRep d
geneTypeRepArgs :: TypeGeneRep d -> [TypeGeneRep d]
showGeneTypeRep :: TypeGeneRep d -> TypeGeneStr d
showExpandTypeArgs :: d -> [TypeGeneStr d]
showExpandTypeArgs dynam = lexByArrow typo
where
typo = showGeneTypeRep $ geneTypeRep dynam我所做的唯一更改是将type更改为data,并删除了typo的类型签名。这个版本的关键之处在于,要现在实例化HeukaryaGene,您必须编写如下内容
instance HeukaryaGene Int where
-- You can instantiate data families with newtypes, too.
newtype TypeGeneStr Int = TGSInt String
data TypeGeneRep Int = TGRInt
showGeneTypeRep TGRInt = TGSInt "Int"也就是说,潜在地有很多(取消)包装要做。但这将会起作用。
您也可以在这里使用函数依赖,但您实际上是在复制此解决方案及其缺点;其思想是您将拥有class HeukaryaGene d tgs tgr | d -> tgs tgr, tgs -> d, tgr -> d,因此知道d、tgs或tgr中的任何一个就足以推断出其他两个。这看起来不错,但这意味着任何给定的类型只能作为基因字符串或基因代表类型使用一次,因此本质上具有与上面的数据系列版本相同的缺点。
另一种解决方案是,如果您从不在showExpandTypeArgs外部调用lexByArrow或showGeneTypeRep,则将它们从类型类中移除,并让用户以其方式实现showExpandTypeArgs。然而,这对geneTypeRepArgs没有帮助,它将不得不删除
最后一个解决方案是不使用类型类,而是自己处理字典。这将是一个非常彻底的重新设计(尽管不一定是一个糟糕的设计),但是如果您真的想要TypeGeneStr和TypeGeneRep的类型同义词,这是我能想到的唯一方法。它看起来像这样:
data HeukaryaGene d tgs tgr =
HeukaryaGene { lexByArrow :: tgs -> [tgs]
, geneTypeRep :: d -> tgr
, geneTypeRepArgs :: tgr -> [tgr]
, showGeneTypeRep :: tgr -> tgs }
showExpandTypeArgs :: d -> [tgs]
showExpandTypeArgs dynam = lexByArrow typo
where typo = showGeneTypeRep $ geneTypeRep dynam然后,以前类型为HeukaryaGene d => t的函数将具有类型HeukaryaGene d tgs tr -> t。在这里,使用-XRecordWildCards (和as-patterns)会有所帮助,允许您编写
getTypeRepArgs HeukaryaGene{..} = geneTypeRepArgs . geneTypeRep如果你想让一些字典有一个不同的showExpandTypeArgs实现,你必须稍微改变一下结构:
data HeukaryaGene d tgs tgr =
HeukaryaGene { lexByArrow :: tgs -> [tgs]
, geneTypeRep :: d -> tgr
, geneTypeRepArgs :: tgr -> [tgr]
, showGeneTypeRep :: tgr -> tgs
, showExpandTypeArgs :: d -> [tgs] }
showExpandTypeArgsDefault :: HeukaryaGene d tgs tgr -> d -> [tgs]
showExpandTypeArgsDefault HeukaryaGene{..} dynam = lexByArrow typo
where typo = showGeneTypeRep $ geneTypeRep dynam然后,您将在初始化期间打结:
hgInt :: HeukaryaGene Int String ()
hgInt = HeukaryaGene { lexByArrow = words
, geneTypeRep = const ()
, geneTypeRepArgs = const []
, showGeneTypeRep = const "Int"
, showExpandTypeArgs = showExpandTypeArgsDefault hgInt }实际上,在这个解决方案中,d在geneTypeRep中可能是多余的,因此在showExpandTypeArgs中是多余的,在HeukaryaGene本身中也是多余的:如果像在Typeable中一样,您只是使用d来挑选类型类,那么在这里就不需要它了。但这将取决于您的具体情况。
发布于 2013-07-21 02:59:21
我发现这个优雅的解决方案是这样的:Incomprehensible error message with type families
类型类定义:
class (
UnTypeGeneStr (TypeGeneStr d) ~ d, UnTypeGeneRep (TypeGeneRep d) ~ d
) => HeukaryaGene d where
type TypeGeneStr d :: *
type TypeGeneRep d :: *
type UnTypeGeneStr o :: *
type UnTypeGeneRep o :: *实例定义:
instance HeukaryaGene Dynamic where
type TypeGeneStr Dynamic = String
type TypeGeneRep Dynamic = TypeRep
type UnTypeGeneStr String = Dynamic
type UnTypeGeneRep TypeRep = Dynamic感谢大家的帮助!!
发布于 2017-03-24 02:55:43
我知道这是一个老问题,但是GHC8.0增加了对injective type synonyms的支持。如果您启用了TypeFamilyDependencies,您的示例应该可以使用以下内容:
class HeukaryaGene d where
type TypeGeneStr d = s | s -> d
type TypeGeneRep d = r | r -> d
...https://stackoverflow.com/questions/17764157
复制相似问题