(xs:Vect n elem) - > Vect(n * 2)elem

时间:2015-11-21 03:36:33

标签: idris

本书Type Driven Development with Idris介绍了这个练习:

  

定义适合签名的可能方法:

two : (xs : Vect n elem) -> Vect (n * 2) elem

我试过了:

two : (xs : Vect n elem) -> Vect (n * 2) elem
two xs = xs ++ xs

但是我收到了以下错误:

*One> :r
Type checking ./One.idr
One.idr:9:5:When checking right hand side of two:
Type mismatch between
        Vect (n + n) elem (Type of xs ++ xs)
and
        Vect (mult n 2) elem (Expected type)

Specifically:
        Type mismatch between
                plus n n
        and
                mult n 2
Holes: Hw1.two

如果我有一个大小为N的Vector,并且需要一个大小为N * 2的Vector,那么将它附加到自身似乎是合理的。

我做错了什么?

1 个答案:

答案 0 :(得分:12)

简短回答

将类型签名更改为two : (xs : Vect n elem) -> Vect (n + n) elem

如果你真的需要那样

前往Vect (n * 2) elem有点复杂。这里:

two' : Vect n elem -> Vect (n * 2) elem
two' {n} xs = rewrite multCommutative n 2 in rewrite plusZeroRightNeutral n in xs ++ xs

您收到该错误消息的原因是,在缩减为正常形式后,类型检查中的相等性是相等的。 n + nmult n 2是平等的,但它们的正常形式并不相同。 (mult n 2是解析类型类后n * 2减少的内容。)

你可以看到mult的定义如下:

*kevinmeredith> :printdef mult
mult : Nat -> Nat -> Nat
mult 0 right = 0
mult (S left) right = plus right (mult left right)

它通过第一个参数的模式匹配来工作。由于two类型签名中的第一个参数是nmult根本无法减少。multCommutative*kevinmeredith> :t multCommutative multCommutative : (left : Nat) -> (right : Nat) -> left * right = right * left 会帮助我们解决问题:

rewrite

我们应用这种平等的最佳工具是two',就像我对:t replace的定义一样。 (如果你想看看如何做到这一点,请在REPL上运行rewrite foo in bar)在foo构造中,a = b类型bar和{{1}具有外部表达式的类型,但所有ab替换。在上面的two'中,我首先使用它将Vect (n * 2)更改为Vect (2 * n)。这可以让mult减少。如果我们查看上面的mult,并将其应用于2,即S (S Z)n,则会获得plus n (mult (S Z) n,然后plus n (plus n (mult Z n)),然后plus n (plus n Z)。你不必自己计算减少量,你可以只应用重写并在最后添加一个洞:

two' : Vect n elem -> Vect (n * 2) elem
two' {n} xs = rewrite multCommutative n 2 in ?aaa

然后问伊德里斯:

*kevinmeredith> :t aaa
  elem : Type
  n : Nat
  xs : Vect n elem
  _rewrite_rule : plus n (plus n 0) = mult n 2
--------------------------------------
aaa : Vect (plus n (plus n 0)) elem

plus n Z没有减少,因为plus是由第一个参数的递归定义的,就像mult一样。 plusZeroRightNeutral为您提供所需的平等:

*kevinmeredith> :t plusZeroRightNeutral 
plusZeroRightNeutral : (left : Nat) -> left + 0 = left

我再次使用与rewrite相同的技术。

:search可让您在图书馆中搜索特定类型的居民。你经常会发现有人为你做过证明工作。

*kevinmeredith> :s (n : Nat) -> n + 0 = n
= Prelude.Nat.multOneLeftNeutral : (right : Nat) ->
                                   fromInteger 1 * right = right


= Prelude.Nat.plusZeroRightNeutral : (left : Nat) ->
                                     left + fromInteger 0 = left


*kevinmeredith> :s (n, m : Nat) -> n * m = m * n
= Prelude.Nat.multCommutative : (left : Nat) ->
                                (right : Nat) -> left * right = right * left

(这个答案适用于Idris版本0.9.20.1)