考虑
[1, 2, 1]
RemoveElem 1 [1, 2, 1]
是
[2, 1]
. 现在,电话
removeElem 1 (There $ There $ Here) ([1, 2, 1] :: SNatVect 3 [1, 2, 1]) :: SNatVect 2 [2, 1]
,应该编译。这是错误的。这个
Elem
[1, 2]
,但类型签名表明它必须是
[2,1]
.
第一,
SNatVect
Nat
论据:
data SNatVect :: forall n. Nat -> Vect n a -> Type where ...
首先是
n
,第二个是未命名的
. 根据结构
,他们总是平等的。它允许
蛇形
作为一个平等的证明来翻倍,但它可能不是这样的意图。你可能是说
data SNatVect (n :: Nat) :: Vect n Nat -> Type where ...
无法在源Haskell中使用
->
语法。然而,当GHC打印这种类型时,有时会得到
SNatVect :: forall (n :: Nat) -> Vect n Nat -> Type
但这是多余的。你可以把
纳特
forall
论证,并从
Vect
s型:
data SNatVect (xs :: Vect n Nat) where
SNatNil :: SNatVect 'Nil
SNatCons :: SNat x -> SNatVect xs -> SNatVect (x '::: xs)
这给了
SNatVect :: forall (n :: Nat). Vect n Nat -> Type
removeElem :: forall (n :: Nat) (x :: Nat) (xs :: Vect (S n) Nat).
Elem x xs -> SNatVect xs -> Vect n Nat
请注意
SNat
参数已不存在,返回类型如何是简单的
. 这个
参数使类型“太大”,所以当函数不起作用时,您会发现它有点起作用。这个
返回类型表示您跳过了步骤。大致上,每个函数都有三种形式:基本函数,
f :: a -> b -> c
;类型级别1,
type family F (x :: a) (y :: b) :: c
;和依赖的那个,
f :: forall (x :: a) (y :: b). Sing x -> Sing y -> Sing (F x y)
. 每种方法都是以“相同”的方式实现的,但是如果不实现前一种方法就试图实现一种方法,肯定会让人感到困惑。
现在,你可以把这个抬起来一点:
data SElem (e :: Elem x (xs :: Vect n k)) where
SHere :: forall x xs. SElem ('Here :: Elem x (x '::: xs))
SThere :: forall x y xs (e :: Elem x xs). SElem e -> SElem ('There e :: Elem x (y '::: xs))
type family RemoveElem (xs :: Vect (S n) a) (e :: Elem x xs) :: Vect n a
removeElem
和
RemoveElem
. 参数的重新排序是因为
e
xs
,因此需要相应地订购。另一种选择是:
xs型
争论是从
福尔
'd-隐式给定到显式给定,然后
Sing xs
最后,您可以编写此函数:
sRemoveElem :: forall (xs :: Vect (S n) Nat) (e :: Elem x xs).
SElem e -> SNatVect xs -> SNatVect (RemoveElem xs e)