【发布时间】:2018-04-05 21:30:36
【问题描述】:
让我们考虑一个谓词,表明列表中的元素是按递增顺序排列的(为简单起见,我们只处理非空列表):
mutual
data Increasing : List a -> Type where
SingleIncreasing : (x : a) -> Increasing [x]
RecIncreasing : Ord a => (x : a) ->
(rest : Increasing xs) ->
(let prf = increasingIsNonEmpty rest
in x <= head xs = True) ->
Increasing (x :: xs)
%name Increasing xsi, ysi, zsi
increasingIsNonEmpty : Increasing xs -> NonEmpty xs
increasingIsNonEmpty (SingleIncreasing y) = IsNonEmpty
increasingIsNonEmpty (RecIncreasing x rest prf) = IsNonEmpty
现在让我们试着用这个谓词写一些有用的引理。假设第一个列表的最后一个元素不大于第二个列表的第一个元素,让我们首先展示连接两个递增列表会产生一个递增列表。这个引理的类型是:
appendIncreasing : Ord a => {xs : List a} ->
(xsi : Increasing xs) ->
(ysi : Increasing ys) ->
{auto leq : let xprf = increasingIsNonEmpty xsi
yprf = increasingIsNonEmpty ysi
in last xs <= head ys = True} ->
Increasing (xs ++ ys)
现在让我们尝试实现它!一种合理的方法似乎是在xsi 上拆分大小写。 xsi 是单个元素的基本情况很简单:
appendIncreasing {leq} (SingleIncreasing x) ysi = RecIncreasing x ysi leq
另一种情况更复杂。给定
appendIncreasing {leq} (RecIncreasing x rest prf) ysi = ?wut
通过依赖leq,然后使用prf 在x 前面添加rest 和ysi 的结果,递归地证明这一点似乎是合理的。此时leq实际上是last (x :: xs) <= head ys = True的证明,而对appendIncreasing的递归调用需要有last xs <= head ys = True的证明。我没有看到直接证明前者暗示后者的好方法,所以让我们回过头来重写并首先编写一个引理,表明列表的最后一个元素不会通过添加到前面来改变:
lastIsLast : (x : a) -> (xs : List a) -> {auto ok : NonEmpty xs} -> last xs = last (x :: xs)
lastIsLast x' [x] = Refl
lastIsLast x' (x :: y :: xs) = lastIsLast x' (y :: xs)
现在我希望能够写作
appendIncreasing {xs = x :: xs} {leq} (RecIncreasing x rest prf) ysi =
let rest' = appendIncreasing {leq = rewrite lastIsLast x xs in leq} rest ysi
in ?wut
但我失败了:
When checking right hand side of appendIncreasing with expected type
Increasing ((x :: xs) ++ ys)
When checking argument leq to Sort.appendIncreasing:
rewriting last xs to last (x :: xs) did not change type last xs <= head ys = True
我该如何解决这个问题?
而且,也许我的证明设计不是最理想的。有没有办法以更有用的方式表达这个谓词?
【问题讨论】:
标签: idris