Haskell 由于Paterson';s条件

Haskell 由于Paterson';s条件,haskell,typeclass,undecidable-instances,Haskell,Typeclass,Undecidable Instances,我正在尝试使用索引嵌套注释构建AST。我添加了一个typeclass,用于在顶层剥离注释,并尝试提供默认实例,有效地表示“如果您知道如何单独剥离注释,那么您就知道如何剥离特定AST节点上的注释。” 因为我的一个树节点是一个Nat索引谓词,它的父节点存在性地量化了这个变量,所以当我尝试为父节点编写实例时,我陷入了Paterson的条件。也就是说,断言中的类型变量比头部中的类型变量多 如果我打开undedicatableinstances,那么GHC无法将变量与kindNat统一起来 如果我进一步打

我正在尝试使用索引嵌套注释构建AST。我添加了一个typeclass,用于在顶层剥离注释,并尝试提供默认实例,有效地表示“如果您知道如何单独剥离注释,那么您就知道如何剥离特定AST节点上的注释。”

因为我的一个树节点是一个
Nat
索引谓词,它的父节点存在性地量化了这个变量,所以当我尝试为父节点编写实例时,我陷入了Paterson的条件。也就是说,断言中的类型变量比头部中的类型变量多

如果我打开
undedicatableinstances
,那么GHC无法将变量与kind
Nat
统一起来

如果我进一步打开
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
    中去掉。