我想要编译:
foo: Vect n String -> Vect n String
foo {n} xs = take n xs
这无法编译,因为编译器无法将n
与n + m
统一起来。我知道这是因为Vect的take
的签名但我无法弄清楚如何在m = 0
显示编译器可以统一它们。
答案 0 :(得分:6)
只是添加到上一个答案,另一种可能性是使用库中现有的plusZeroRightNeutral
引理重写内联:
foo: Vect n String -> Vect n String
foo {n} xs = let xs' : Vect (n + 0) String
= rewrite (plusZeroRightNeutral n) in xs in
take n xs'
伊德里斯在统一中遇到的困难是因为它不愿意在应用中推断出m
:
take : (n : Nat) -> Vect (n + m) a -> Vect n a
您已经Vect n String
想要Vect (n + m) a
- 它已经很高兴地将a
与String
统一起来了,因为Vect
是一种类型构造函数,但不愿意将n
与n + m
统一起来,因为通常它不能反转函数。你和我可以说m
必须为零,但伊德里斯并不那么聪明。
答案 1 :(得分:3)
Idris无法将n
与n + m
统一起来,因为它不知道n = n + 0
。你需要通过手动证明这一点来帮助他。
首先,为什么需要这个证明。原因是take
期望Vect (n+m) a
:
Idris> :t Vect.take
Prelude.Vect.take : (n : Nat) -> Vect (n + m) a -> Vect n a
所以,这将是类型检查
foo: Vect (n + 0) String -> Vect n String
foo {n} xs = take n xs
您需要一种方法将Vect n a
转换为Vect (n + 0) a
:
addNothing : {n : Nat} -> {a : Type} -> Vect n a -> Vect (n+Z) a
可以使用replace
函数:
Idris> :t replace
replace : (x = y) -> P x -> P y
但现在你需要一个n = n + 0
的证明。这是(与其余代码一起):
plusAddZero : (n : Nat) -> n = n + 0
plusAddZero = proof
intros
rewrite (plusCommutative n 0)
trivial
addNothing : {n : Nat} -> {a : Type} -> Vect n a -> Vect (n + 0) a
addNothing {n} {a} = replace {P = \m => Vect m a} (plusAddZero n)
foo : Vect n String -> Vect n String
foo {n} xs = Vect.take n (addNothing xs)
对于这么简单的功能似乎太过分了。希望有人能展示更简洁的解决方案。