我正在尝试使用索引嵌套注释构建 AST。我添加了一个用于在顶层剥离注释的类型类,并尝试提供默认实例,有效地说明“如果您知道如何自行剥离注释,那么您就知道如何在特定 AST 节点处剥离注释。”
由于我的一个树节点是一个Nat
索引谓词,并且它的父节点存在地量化了这个变量,所以当我尝试为父节点编写实例时,我陷入了帕特森的条件。也就是说,我在断言中的类型变量比在头脑中的要多。
如果我打开UndecidableInstances
,则 GHC 无法将变量与 kind 统一起来Nat
。
如果我进一步打开AllowAmbiguousTypes
,那么我会得到一个更荒谬的错误,它说它找不到实例,尽管它正在寻找的实例在类型实例的断言中。
我的问题是:
- 这实际上是一个不好的实例,还是类型检查器过于保守?
- 如果它不好或无法解决问题,我还能如何提供这种默认的剥离行为?
这是最小的代码(我去掉了对类型错误不重要的位,所以有些位可能看起来是多余的):
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
module Constraint where
data AnnType = ABase
data family PredicateAnn (a :: AnnType)
data instance PredicateAnn (a :: AnnType) = PABase
data Nat = Zero | Succ Nat
data Predicate (n :: Nat) (a :: AnnType) = Predicate
data Literal (a :: AnnType) = forall n. Literal (Predicate n a)
class PeelableAST (ast :: AnnType -> *) (ann :: AnnType -> AnnType) where
peel :: ast (ann a) -> ast a
class PeelableAnn (f :: AnnType -> *) (ann :: AnnType -> AnnType) where
peelA :: f (ann a) -> f a
instance PeelableAST (Predicate n) ann
=> PeelableAST Literal ann where
peel (Literal predicate) = Literal (peel predicate)
instance PeelableAnn PredicateAnn ann => PeelableAST (Predicate n) ann where
peel Predicate = Predicate
这是没有的确切错误UndecidableInstances
:
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: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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
这是一个AllowAmbiguousTypes
:
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 建议的那样,一种解决方案是在实例中进行PeelableAnn PredicateAnn ann
断言。PeelableAST Literal ann
但是,我从来没有peelA
在定义中使用由 PeelableAnnPeelableAST Literal ann
定义的,我希望这个实例作为默认行为并且能够通过直接提供一个PeelableAST (Predicate n) ann
实例来覆盖它。换句话说,剥离可能本质上是上下文相关的。
既然PeelableAnn PredicateAnn ann
是要求PeelableAST (Predicate n) ann
,我觉得GHC应该能找到并满足这个条件。
我可以简单地拥有一个虚假PeelableAnn PredicateAnn ann
实例,而只会被更具体的实例忽略,但这很hacky