使用幻像类型时避免冗余约束

时间:2017-01-09 08:20:53

标签: haskell ghc gadt

这是我正在尝试编写的一个简化的,也许是愚蠢的例子(更复杂,涉及列表长度的编译时编码)。

鉴于以下内容:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GADTs #-}

data D (a :: Bool) where
  D :: Bool -> D a

我想要以下函数g

g :: D a -> Bool
g (D x) = x == a

当然这不会编译,因为a是一个类型,而不是一个值。

这是一个可能的解决方案:

class C (a :: Bool) where
  f :: D a -> Bool

instance C True where
  f (D x) = x == True

instance C False where
  f (D x) = x == False

g :: (C a) => D a -> Bool
g = f

但是我必须向g添加约束,这似乎是a :: Bool的冗余,并且我已经为Bool的所有情况提供了实例。

无论如何,我可以写g使其具有签名:

g :: D a -> Bool 

即。不需要额外的约束?

1 个答案:

答案 0 :(得分:7)

不,这是不可能的,因为我可以为您提供D Any类型的完美价值,其中Any已定义

type family Any :: k where {}

你能做的就是写一个更普遍有用的课程:

data SBool a where
  SFalse :: SBool 'False
  STrue :: SBool 'True

sBoolToBool :: SBool a -> Bool
sBoolToBool SFalse = False
sBoolToBool STrue = True

class KnownBool a where
  knownBool :: SBool a
instance KnownBool 'False where
  knownBool = SFalse
instance KnownBool 'True where
  knownBool = STrue

当然,如果你没有将这些类型用于其他任何事情,那么所有这些机器都是过度的。