Haskell 使用虚拟类型时避免冗余约束

Haskell 使用虚拟类型时避免冗余约束,haskell,ghc,gadt,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是一个

这是一个简化的、也许是愚蠢的示例,说明了我试图编写的代码(它更复杂,并且涉及列表长度的编译时编码)

鉴于以下情况:

{-# 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 

i、 e.不需要附加约束?

不,这是不可能的,因为我可以为您提供类型为
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

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

这里的部分问题是Haskell在运行时擦除类型:即使'g::forall a。D a->Bool`在运行时
g
未传递
a
的“值”。为了避免这种情况,您需要一个类型类约束(在运行时传递一个字典)或一个单例,如下所示。也许将来我们会得到
g::pia
用于非擦除类型,但目前……您也可以将其视为所有始终是参数化的:
g
的行为不能依赖于类型
a
pi
将是所有的非参数对应项。感谢您的评论。我已经解决了这个问题,在任何我想在运行时区分类型的地方提供了单独的构造函数。