基于类型级别谓词的实例?

时间:2014-11-06 22:48:58

标签: haskell types

要创建一个接受类型级自然Z,(S Z),(S(S Z))...等的类型类,您可以简单地递归声明实例:

data Z
data S a

class Type a

instance Type Z
instance Type (S a)

是否可以基于类型级别谓词创建类型类实例?例如,我希望能够说:

{-# LANGUAGE MultiParamTypeClasses #-}
class Type a b
instance Type x y when (x :+: y == 8)

其中:+:是类型级别添加,==是来自Data.Type.Equality的类型级别相等,因此只为最多加起来为8的nat对创建实例。

Haskell中的符号是否类似?如果没有,这样的事情将如何实现?

编辑:此帖子受到启发by the Haskell wiki article on smart constructors,其中声明了类型类InBounds以静态验证传递给智能构造函数的幻像类型参数是否在Nat s的某个范围内,聪明的构造函数是:

resistor :: InBounds size => size -> Resistor size
resistor _ = Resistor

尝试在我的示例中执行类似的操作(在使用leftaroundabout'回答之后)给出了一个错误:

construct :: (Type a b) => a -> b -> MyType a b
construct _ _ = MyType

>>> Expected a type, but a has kind Nat…

来自Haskell wiki的示例之所以有效,是因为它没有使用DataKinds,是否可以将类型Nat传递给值级函数?

2 个答案:

答案 0 :(得分:8)

您需要使用的不是等式谓词,而是使用等式约束(它已融入语言,使用-XGADTs启用)。

{-# LANGUAGE KindSignatures, DataKinds, MultiParamTypeClasses, FlexibleInstances, GADTs #-}

import GHC.TypeLits

class Type (a :: Nat) (b :: Nat)

instance (a + b) ~ 8 => Type a b

请注意,这并不一定像它看起来那样有用 - 等式约束不会以某种方式枚举所有组合加起来为8,而是允许所有Nat -pairs是实例,只需要一个证明,它们加起来为8.你可以使用这个证明,但我怀疑Haskell仍然只是排序 - 独立类型的性质使这项工作做得很好。

答案 1 :(得分:1)

您可以编写类型级别函数

type family NatEq (a :: Nat) (b :: Nat) :: Bool
type instance NatEq 0 0 = True
...

然后

instance Type' (NatEq (a + b) 8) a b => Type a b
class Type' (x :: Bool) (a :: Nat) (b :: Nat) where ...
instance Type' True a b where ...
-- If you wanted a different behaviour otherwise:
-- instance Type' False a b where ...

当然,您需要启用一系列扩展程序。

如果ab是常量,则此工作正常,因此a+b可以缩减为8(或其他常量)。如果它们不是常数,请不要期望GHC为您证明这个等式。这是(使用Int代替Nat),不要期望Type x (8-x)得到解决。