类型族实例证明是否可行?

时间:2012-10-18 17:30:28

标签: haskell type-families type-level-computation

首先,我从一些典型的类型级自然数字开始。

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}

data Nat = Z | S Nat

type family Plus (n :: Nat) (m :: Nat) :: Nat
type instance Plus Z m = m
type instance Plus (S n) m = S (Plus n m)

所以我想创建一个表示n维网格的数据类型。 (对Evaluating cellular automata is comonadic所见内容的概括。)

data U (n :: Nat) x where
  Point     :: x                           -> U Z     x
  Dimension :: [U n x] -> U n x -> [U n x] -> U (S n) x

我们的想法是,U num x类型是num的{​​{1}}维网格的类型,它“聚焦”在网格中的特定点上。

所以我想把它变成一个comonad,我注意到我可以做这个潜在有用的功能:

x

我们现在可以实现一个“维度连接”,根据这个组合子,将m维网格的n维网格转换为(n + m)维网格。在处理将产生网格网格的ufold :: (x -> U m r) -> U n x -> U (Plus n m) r ufold f (Point x) = f x ufold f (Dimension ls mid rs) = Dimension (map (ufold f) ls) (ufold f mid) (map (ufold f) rs) 的结果时,这将派上用场。

cojoin

到目前为止一切顺利。我还注意到dimJoin :: U n (U m x) -> U (Plus n m) x dimJoin = ufold id 实例可以用Functor

来编写
ufold

但是,这会导致类型错误。

instance Functor (U n) where
  fmap f = ufold (\x -> Point (f x))

但是如果我们掀起一些复制意大利面,那么类型错误就会消失。

Couldn't match type `n' with `Plus n 'Z'

我讨厌复制意大利面的味道,所以我的问题是这个。 如何判断instance Functor (U n) where fmap f (Point x) = Point (f x) fmap f (Dimension ls mid rs) = Dimension (map (fmap f) ls) (fmap f mid) (map (fmap f) rs) 等于Plus n Z 的类型系统?问题是:您不能对类型系列实例进行更改,这会导致n产生类似的类型错误。

1 个答案:

答案 0 :(得分:5)

你需要的是一个很好的命题相等类型:

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

data Nat = Z | S Nat

type family Plus (n :: Nat) (m :: Nat) :: Nat
type instance Plus Z m = m
type instance Plus (S n) m = S (Plus n m)

data (:=) :: k -> k -> * where
  Refl :: a := a

data Natural (n :: Nat) where
  Zero :: Natural Z
  Suc  :: Natural n -> Natural (S n)

plusZero :: Natural n -> n := (n `Plus` Z)
plusZero Zero = Refl
plusZero (Suc n) | Refl <- plusZero n = Refl

这允许您通过Refl上的模式匹配来证明关于您的类型的任意事物,并将这些知识带入本地范围。

一个令人讨厌的事情是我的plusZero证明要求对自然问题进行归纳,默认情况下你无法做到(因为它在运行时不存在)。但是,生成Natural证人的类型类很容易。

您的特定情况的另一个选项可能只是在您的类型定义中将参数反转为加号,以便您在左侧获得Z并自动减少。确保你的类型尽可能简单,这通常是一个很好的第一步,但是无论如何你都经常需要命题平等来处理更复杂的事情。