如何在Idris中重写函数体,以便类型对应于函数签名和整个事物编译

时间:2014-07-24 17:14:47

标签: dependent-type idris

我想要编译:

foo: Vect n String -> Vect n String
foo {n} xs = take n xs

这无法编译,因为编译器无法将nn + m统一起来。我知道这是因为Vect的take的签名但我无法弄清楚如何在m = 0显示编译器可以统一它们。

2 个答案:

答案 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 - 它已经很高兴地将aString统一起来了,因为Vect是一种类型构造函数,但不愿意将nn + m统一起来,因为通常它不能反转函数。你和我可以说m必须为零,但伊德里斯并不那么聪明。

答案 1 :(得分:3)

Idris无法将nn + 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)

对于这么简单的功能似乎太过分了。希望有人能展示更简洁的解决方案。