类型解构

时间:2013-01-11 06:44:57

标签: haskell types type-constructor

我的数据类型总是至少有两个参数,最后两个参数分别是'q'和'm':

{-# LANGUAGE TypeFamilies, FlexibleContexts, UndecidableInstances, TypeOperators, DataKinds, ConstraintKinds, FlexibleInstances #-}

data D1 q m = D1 q
data D2 t q m = D2 q

class Foo a where -- a has kind * -> *
   f :: a x -> a x

class (Foo b) => Bar b where -- b has kind * -> *
   -- the purpose of g is to change ONE type parameter, while fixing the rest
   -- the intent of the equality constraints is to decompose the parameter b into
   -- its base type and 'q' parameter, then use the same base type with a *different*
   -- `q` parameter for the answer
   g :: (b ~ bBase q1, b' ~ bBase q2) => b m -> b' m

instance (Foo (D2 t q), Integral q) => Bar (D2 t q) where
   g (D2 q) = D2 $ fromIntegral q -- LINE 1

此程序导致错误

Could not deduce (bBase ~ D2 t0) (LINE 1)

当我编写实例时,我当然打算bBase ~ D2 t。我想t不会以某种方式绑定(因此引入了t0),我不知道GHC是否可以解构这种类型。或许我只是做些傻事。

更重要的是,如果我将参数设置为Bar有类型* - >,则不需要这种类型的相等/类型解构。 * - > *。但后来我无法强制执行Foo约束:

class (Foo (b q)) => Bar b where -- b has kind * -> * -> *
  g :: b q m -> q b' -- this signature is now quite simple, and I would have no problem implementing it

这不起作用,因为q不是Bar的参数,我不想要它到Bar的参数。

我找到了一个使用两个额外“虚拟”关联类型的解决方案,但如果我不需要它们,我真的不喜欢它们:

class (Foo b, b ~ (BBase b) (BMod b)) => Bar b where -- b has kind * -> *
  type BBase b :: * -> * -> *
  type BMod b :: *

  g :: (Qux (BMod b), Qux q') => b m -> (BBase b) q' m

instance (Foo (D2 t q), Integral q) => Bar (D2 t q) where
  type BBase (D2 t q) = D2 t
  type BMod (D2 t q) = q

  g (D2 q) = D2 $ fromIntegral q

这是有效的,但它相当于明确地解构了类型,我认为在实例的简单类型下我认为这是不必要的。

我正在寻找这两种方法的解决方案:要么告诉我如何在“更多应用”类型上强制执行类约束,要么告诉我如何制作GHC解构类型。

谢谢!

1 个答案:

答案 0 :(得分:1)

根据您的描述,您有类型b' :: * -> * -> *,您希望约束所应用的b' t :: * -> *(适用于所有t)。

当你总结时,你要么需要解构一个类型,这是你在这里的尝试 从b :: * -> *开始,假设是类型的结果 应用程序b = b' t,或强制执行约束更多应用"而是类型 从b' :: * -> * -> *开始。

解构类型是不可能的,因为编译器不知道b是否是可解构的"。实际上,它可能不是,例如,我可以创建一个实例instance Bar Maybe,但Maybe无法解构为b' :: * -> * -> *类型和某种类型t :: *

从类型b' :: * -> * -> *开始,b'的应用程序的约束可以移动到类的主体中,其中变量被量化:

  class Bar (b :: * -> * -> *) where
      g :: (Foo (b q1), Foo (b q2)) => b q1 m -> b q2 m

对于你的例子,还有一个问题:q1和q2可能有自己的约束, 例如对于D2实例,您需要Integral约束。但是,Bar修复了q1q2对所有实例的约束(在本例中为空约束)。一个解决方案是使用"约束 - 类型的家庭"允许实例指定自己的约束:

  class Bar (b :: * -> * -> *) where
      type Constr b t :: Constraint
      g :: (Foo (b q1), Foo (b q2), Constr b q1, Constr b q2) => b q1 m -> b q2 m

(包括{-# LANGUAGE ConstraintKinds #-}和导入GHC.Prim

然后您可以编写D2实例:

   instance Bar (D2 t) where
      type Constr (D2 t) q = Integral q
      g (D2 q) = D2 $ fromIntegral q