Haskell-GADT模式与类约束匹配

时间:2018-09-28 23:59:15

标签: haskell pattern-matching gadt

考虑以下示例

{-# LANGUAGE DataKinds, GADTs #-}
data Phantom = A | B
data Foo (a :: Phantom) where
  FooA :: Foo 'A
  FooB :: Foo 'B
class PhantomConstraint (a :: Phantom)
instance PhantomConstraint 'A -- Note: No instance for 'B
someFunc :: PhantomConstraint a => Foo a -> ()
someFunc FooA = ()

如果我做这样的事情,GHC会抱怨someFunc的模式匹配并不详尽,但是,如果我尝试包括FooB的情况(出于特定领域的原因我不想这样做)它抱怨无法为PhantomConstraint推论Foo 'B的实例

有什么方法可以使GADT模式匹配了解类型类约束,从而消除模式匹配所需的武器?

编辑:有关我想做什么的更多详细信息。我有一些类型都有点相关但具有不同属性的类型。在OO世界中,这就是人们使用子类型化和继承的目的。但是,在FP社区中,共识似乎是没有真正好的子类型化方法,因此在这种情况下,我需要解决一下。因此,我有一个统一所有类型的GADT,但该类型具有不同的参数。然后,我继续在类型参数(由datakinds启用,没有术语表示形式)上编写不同的typeclass和typeclass实例。我希望能够表达这些数据类型中的某些类型具有其他属性所不具有的属性,但是它们确实共享某些公共属性,因此我真的不想破坏该类型。我可以预见的唯一其他选择是在类型部分上创建分类法,但随后DataKinds类型就搞砸了。

1 个答案:

答案 0 :(得分:2)

我无法重现该问题。在GHCi 8.4.3中加载时没有警告或错误。

{-# LANGUAGE GADTs, DataKinds, KindSignatures #-}
{-# OPTIONS -Wall #-}
module GADTwarning2 where

data Phantom = A | B

data Foo (a :: Phantom) where
  FooA :: Foo 'A
  FooB :: Foo 'B

class PhantomConstraint (a :: Phantom)

instance PhantomConstraint 'A -- Note: No instance for 'B

someFunc :: PhantomConstraint a => Foo a -> ()
someFunc FooA = ()
someFunc FooB = ()

正如luqui在评论中解释的那样,我们不能避免FooB的情况,因为类型类是开放的,并且另一个实例可以在以后由另一个模块添加,从而使模式匹配变得不完整。

如果您完全确定除了A以外的其他实例,则可以尝试使用

class a ~ 'A => PhantomConstraint (a :: Phantom)

或者,如果索引a可以是'A'B,但不能是第三个构造函数'C,那么我们可以尝试验证这一事实:

class PhantomConstraint (a :: Phantom) where
   aIsAOrB :: Either (a :~: 'A) (a :~: 'B)

,然后再利用此成员。