我正在尝试使用索引嵌套注释构建AST。我在顶级添加了一个用于剥离注释的类型类,并尝试提供默认实例,该实例有效地表示:“如果您知道如何剥离注释,那么您将知道如何在特定的AST节点处剥离注释。”
由于我的树节点之一是一个Nat
索引的谓词,并且其父节点存在地对该变量进行量化,因此当我尝试为父节点编写实例时,我陷入了Paterson的状况。也就是说,我的断言中的类型变量比头部中的要多。
如果我打开UndecidableInstances
,则GHC无法统一类型为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
定义中PeelableAnn定义的PeelableAST Literal ann
,并且我希望此实例具有默认行为,并可以通过直接提供一个PeelableAST (Predicate n) ann
实例来覆盖它。换句话说,剥离可能是与生俱来的。
由于PeelableAnn PredicateAnn ann
要求PeelableAST (Predicate n) ann
,所以我认为GHC应该能够找到并满足此条件。
我可以简单地拥有一个伪造的PeelableAnn PredicateAnn ann
实例,而只是被更具体的实例所忽略,但这确实很hacky
答案 0 :(得分:3)
在您的PeelableAST Literal ann
实例中,您使用PeelableAST (Predicate n) ann
实例。如果类型检查器要使用该实例,则它必须验证其前提,即PeelableAnn PredicateAnn ann
成立。但这并不知道,因为您尚未将其设为PeelableAST Literal ann
实例的先决条件。
没关系;它很容易修复,可让您完全避免使用歧义类型。只需添加它担心的前提作为您PeelableAST Literal ann
实例的前提即可。确实,由于现在这是两个实例的前提条件,因此您也可以删除PeelableAnn PredicateAnn ann
前提条件,因为这种新的更强大的条件暗示了该前提条件。所以:
instance PeelableAnn PredicateAnn ann => PeelableAST Literal ann where
peel (Literal predicate) = Literal (peel predicate)
您可以删除AllowAmbiguousTypes
,尽管仍然需要UndecidableInstances
,因为PeelableAnn PredicateAnn ann
在结构上显然不小于PeelableAST Literal ann
。