首先,我从一些典型的类型级自然数开始。
{-# 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 维网格的数据类型。(在评估元胞自动机中发现的内容的概括是 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
是 s 的一num
维网格的类型x
,它“聚焦”在网格中的特定点上。
所以我想把它做成一个comonad,我注意到我可以做这个潜在有用的功能:
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)
就这个组合器而言,我们现在可以实现一个“维度连接”,将 m 维网格的 n 维网格转换为 (n+m) 维网格。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
?问题是:您不能对会导致dimJoin
产生类似类型错误的类型族实例进行更改。