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
将是所有的非参数对应项。感谢您的评论。我已经解决了这个问题,在任何我想在运行时区分类型的地方提供了单独的构造函数。