Haskell 由于Paterson';s条件
我正在尝试使用索引嵌套注释构建AST。我添加了一个typeclass,用于在顶层剥离注释,并尝试提供默认实例,有效地表示“如果您知道如何单独剥离注释,那么您就知道如何剥离特定AST节点上的注释。” 因为我的一个树节点是一个Haskell 由于Paterson';s条件,haskell,typeclass,undecidable-instances,Haskell,Typeclass,Undecidable Instances,我正在尝试使用索引嵌套注释构建AST。我添加了一个typeclass,用于在顶层剥离注释,并尝试提供默认实例,有效地表示“如果您知道如何单独剥离注释,那么您就知道如何剥离特定AST节点上的注释。” 因为我的一个树节点是一个Nat索引谓词,它的父节点存在性地量化了这个变量,所以当我尝试为父节点编写实例时,我陷入了Paterson的条件。也就是说,断言中的类型变量比头部中的类型变量多 如果我打开undedicatableinstances,那么GHC无法将变量与kindNat统一起来 如果我进一步打
Nat
索引谓词,它的父节点存在性地量化了这个变量,所以当我尝试为父节点编写实例时,我陷入了Paterson的条件。也就是说,断言中的类型变量比头部中的类型变量多
如果我打开undedicatableinstances
,那么GHC无法将变量与kindNat
统一起来
如果我进一步打开AllowAmbiguousTypes
,我会得到一个更荒谬的错误,它说它找不到实例,尽管它正在寻找的实例在类型实例的断言中
我的问题是:
不可判定实例的确切错误:
src/Constraint.hs:27:10: error:
• Variable ‘n’ occurs more often
in the constraint ‘PeelableAST (Predicate n) ann’
than in the instance head
(Use UndecidableInstances to permit this)
• In the instance declaration for ‘PeelableAST Literal ann’
|
27 | instance PeelableAST (Predicate n) ann
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
src/Constraint.hs:31:39: error:
• Could not deduce (PeelableAnn PredicateAnn ann)
arising from a use of ‘peel’
from the context: PeelableAST (Predicate n) ann
bound by the instance declaration
at src/Constraint.hs:(29,10)-(30,35)
• In the first argument of ‘Literal’, namely ‘(peel predicate)’
In the expression: Literal (peel predicate)
In an equation for ‘peel’:
peel (Literal predicate) = Literal (peel predicate)
|
31 | peel (Literal predicate) = Literal (peel predicate)
| ^^^^^^^^^^^^^^
这里有一个:
src/Constraint.hs:28:10: error:
• Could not deduce (PeelableAST (Predicate n0) ann)
from the context: PeelableAST (Predicate n) ann
bound by an instance declaration:
forall (n :: Nat) (ann :: AnnType -> AnnType).
PeelableAST (Predicate n) ann =>
PeelableAST Literal ann
at src/Constraint.hs:(28,10)-(29,35)
The type variable ‘n0’ is ambiguous
• In the ambiguity check for an instance declaration
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the instance declaration for ‘PeelableAST Literal ann’
|
28 | instance PeelableAST (Predicate n) ann
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
下面是一个带有AllowAmbigUstypes
:
src/Constraint.hs:27:10: error:
• Variable ‘n’ occurs more often
in the constraint ‘PeelableAST (Predicate n) ann’
than in the instance head
(Use UndecidableInstances to permit this)
• In the instance declaration for ‘PeelableAST Literal ann’
|
27 | instance PeelableAST (Predicate n) ann
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
src/Constraint.hs:31:39: error:
• Could not deduce (PeelableAnn PredicateAnn ann)
arising from a use of ‘peel’
from the context: PeelableAST (Predicate n) ann
bound by the instance declaration
at src/Constraint.hs:(29,10)-(30,35)
• In the first argument of ‘Literal’, namely ‘(peel predicate)’
In the expression: Literal (peel predicate)
In an equation for ‘peel’:
peel (Literal predicate) = Literal (peel predicate)
|
31 | peel (Literal predicate) = Literal (peel predicate)
| ^^^^^^^^^^^^^^
编辑:
正如Daniel Wagner所建议的,一种解决方案是在peealableAnn-PredicateAnn-ann
实例中创建一个断言。但是,我从未在peeableast Literal ann
定义中使用peeableann定义的peelA
,我希望此实例作为默认行为,并能够通过直接提供peeableast(谓词n)ann
实例来覆盖它。换句话说,剥离可能具有内在的上下文关系
由于peeableann谓词ann
是peeableast(谓词n)ann
所必需的,我觉得GHC应该能够找到并满足这个条件
我可以简单地创建一个伪peeableann PredicateAnn ann
实例,只被更具体的一个实例忽略,但这是非常粗糙的在您的peeableast Literal ann
实例中,您使用peeableast(谓词n)ann
实例。如果类型检查器想要使用该实例,它必须验证其先决条件,即peeableann-PredicateAnn-ann
有效。但它不知道这一点,因为您没有将它作为peealableEast文本ann
实例的先决条件
没关系;它很容易修复,并允许您完全避免不明确的类型。只需添加它担心的先决条件,作为您peealableast-Literal-ann
实例的先决条件。事实上,由于它现在是两个实例的先决条件,因此您还可以删除peealableann-PredicateAnn-ann
先决条件,正如这个新的更强的条件所暗示的那样。因此:
instance PeelableAnn PredicateAnn ann => PeelableAST Literal ann where
peel (Literal predicate) = Literal (peel predicate)
然后,您可以删除AllowAmbiguousTypes
,尽管仍然需要不可判定的实例
,因为peeballeann-PredicateAnn-ann
在结构上明显小于peeballeast-Literal-ann,感谢您的快速回复。我自己也意识到了这个解决方案,但我觉得有点不满意。我觉得GHC应该能够从peealableEast(Predicate n)ann
实例中找出peealableann PredicateAnn
应该包含的内容。特别是因为这些都是默认实例,我应该能够为特定的ann
编写peealableast(谓词n)ann
实例,并让它由默认的peealableast Literal ann
实例拾取。如果peealableEast自由ann
还需要一个peealableann-PredicateAnn
实例,这就不起作用了。@Madgen啊,我怀疑这里有第二个误解:根据您编写的前提条件,我们知道peealableEast(Predicate n)ann
,但在peealableEast Literal ann
实例中,你打开一个存在式,因此需要一个peealableEast(谓词n')ann
,对于一些n'
,它不等于n
!因此,将前置条件从peealableEast(谓词n)ann
升级到peealableann-PredicateAnn
实质上就是从exists n升级。可剥离东(谓词n)ann
到所有n的。PeealableEast(谓词n)ann
——在这一点上,我们可以根据需要选择n~n'
。@Madgen换句话说,你当前的方法注定要失败。您可以通过让Literal
为您包装一个peealableEast
的实例来恢复,但这样您就无法生成Literal
s,因为您没有相应的peealableEast
,您必须放弃当前的peealableEast(谓词n)ann
捕获所有实例,以支持更具体的实例。如果这听起来很有趣的话,我很乐意添加一个小片段,告诉你怎么做。我想这可能会奏效。这是否意味着仅仅改变了Literal
的定义,这样我就有了forall n ann。PeelableEast(谓词n)ann=>Literal…
?如果是这样的话,仍然不是非常理想,因为我还需要一个类似的可分解的,并且一个人只能将这么多类型类打包到数据类型中…@Madgen是的,这是完全正确的——尽管你可能想把ann
从中去掉。