要创建一个接受类型级自然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
传递给值级函数?
答案 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 ...
当然,您需要启用一系列扩展程序。
如果a
和b
是常量,则此工作正常,因此a+b
可以缩减为8
(或其他常量)。如果它们不是常数,请不要期望GHC为您证明这个等式。这是(使用Int
代替Nat
),不要期望Type x (8-x)
得到解决。