不能通过依赖打字来推断

时间:2017-12-14 07:36:04

标签: haskell dependent-type

我一直在玩一些具有依赖类型的cofree isomporphisms,并且收到的错误消息对我来说似乎是无稽之谈。

我依赖类型的cofree

data Cofree (n :: Nat) f a where
  (:<<) :: a -> f (Cofree n f a) -> Cofree ('S n) f a

和同构代码

class Iso a b where
  toA :: b -> a
  toB :: a -> b

和我的(非常基本的)实例(它缺少很多东西,但我想首先处理基础知识)

instance Iso (Vec ('S n) a) (Cofree ('S n) Maybe a) where
  toA :: Cofree ('S n) Maybe a -> Vec ('S n) a
  toA (x :<< Nothing) = VCons x VNil

我认为这是最基本的事情,但它仍然会输入错误。

错误本身:

interactive>:224:127: error:
    * Could not deduce: n1 ~ 'Z
      from the context: 'S n ~ 'S n1
        bound by a pattern with constructor:
               :<< :: forall (f :: * -> *) a (n :: Nat).
                      a -> f (Cofree n f a) -> Cofree ('S n) f a,
             in an equation for `toA'
    at <interactive>:224:112-122
  `n1' is a rigid type variable bound by
    a pattern with constructor:
      :<< :: forall (f :: * -> *) a (n :: Nat).
             a -> f (Cofree n f a) -> Cofree ('S n) f a,
    in an equation for `toA'
    at <interactive>:224:112
  Expected type: Vec ('S n) a
    Actual type: Vec ('S 'Z) a
* In the expression: VCons x VNil
  In an equation for `toA': toA (x :<< Nothing) = VCons x VNil
  In the instance declaration for
    `Iso (Vec ('S n) a) (Cofree ('S n) Maybe a)' 

这看起来很奇怪,因为我不明白为什么它不能用'Z in in n1代入类型方程,因为这似乎解决了它。

我尝试过做洞的事情(所以在我的定义中,我有:

= _ $ VCons x VNil

返回

 Found hole: _ :: Vec ('S 'Z) a -> Vec ('S n) a

这看起来很奇怪,因为为什么我不能在那里提供id,它将'Z与n匹配,并且繁荣,解决了?

顺便说一下,我认为Nat和Vec的定义非常正常,所以我不想用比我需要的更多的代码来混淆这篇文章,所以如果对某些人来说更容易,我可以提供它们。

编辑: 我使用的Nat是

data Nat = Z | S Nat

我使用的Vec是

data Vec (n :: Nat) a where
  VNil :: Vec 'Z a
  VCons :: a -> Vec n a -> Vec ('S n) a

并且不需要导入,但GADT,DataKinds,MultiParamTypeClasses,KindSignatures和FlexibleInstances是必需的,也许PolyKinds?我不太记得。

2 个答案:

答案 0 :(得分:1)

您无法选择n的值。 toA的来电者选择了这一点,toA的定义必须与任何选择兼容。

由于无法保证呼叫者选择n ~ 'Z,因此类型检查器会抱怨。

的确,x :<< Nothing可以有Cofree ('S n) Maybe a类型 但VCons x VNil只有Vec ('S 'Z) a类型,而不是Vec ('S n) a

答案 1 :(得分:1)

此处的问题是,您可以随时选择Maybe Nothing构造函数,但只能使用Vec VNil索引为Z时的构造函数。这种不匹配使得同构无法实现。

然而,您可以通过以下方式挽救这种情况:

  • 更改已编入索引的Cofree的定义,以使其参数f也被编入索引
  • 引入Maybe的变体,当索引为Nothing时,您只能使用Z构造函数

换句话说:

data ICofree (n :: Nat) f a where
  (:<<) :: a -> f n (ICofree n f a) -> ICofree ('S n) f a

data IMaybe (n :: Nat) a where
  INothing :: IMaybe 'Z a
  IJust    :: a -> IMaybe ('S n) a

instance Iso (Vec n a) (ICofree n IMaybe a) where
  toA (x :<< INothing) = VCons x VNil
  toA (x :<< IJust xs) = VCons x (toA xs)

  toB (VCons x VNil)       = x :<< INothing
  toB (VCons x xs@VCons{}) = x :<< IJust (toB xs)

a self-contained gist使用正确的导入,语言扩展和定义。