【发布时间】:2018-05-01 17:40:57
【问题描述】:
假设我们有一个函数merge,它只是合并两个列表:
Order : Type -> Type
Order a = a -> a -> Bool
merge : (f : Order a) -> (xs : List a) -> (ys : List a) -> List a
merge f xs [] = xs
merge f [] ys = ys
merge f (x :: xs) (y :: ys) = case x `f` y of
True => x :: merge f xs (y :: ys)
False => y :: merge f (x :: xs) ys
我们想证明一些聪明的东西,例如,合并两个非空列表会产生一个非空列表:
mergePreservesNonEmpty : (f : Order a) ->
(xs : List a) -> (ys : List a) ->
{auto xsok : NonEmpty xs} -> {auto ysok : NonEmpty ys} ->
NonEmpty (merge f xs ys)
mergePreservesNonEmpty f (x :: xs) (y :: ys) = ?wut
检查孔的类型wut 给我们
wut : NonEmpty (case f x y of True => x :: merge f xs (y :: ys) False => y :: merge f (x :: xs) ys)
到目前为止是有道理的!因此,让我们按照这种类型的建议继续进行大小写拆分:
mergePreservesNonEmpty f (x :: xs) (y :: ys) = case x `f` y of
True => ?wut_1
False => ?wut_2
希望wut_1 和wut_2 的类型能够匹配merge 的case 表达式的相应分支似乎是合理的(所以wut_1 会类似于NonEmpty (x :: merge f xs (y :: ys)),可以立即满足),但我们的希望落空了:类型与原始 wut 相同。
确实,唯一的方法似乎是使用with-clause:
mergePreservesNonEmpty f (x :: xs) (y :: ys) with (x `f` y)
mergePreservesNonEmpty f (x :: xs) (y :: ys) | True = ?wut_1
mergePreservesNonEmpty f (x :: xs) (y :: ys) | False = ?wut_2
在这种情况下,类型将符合预期,但这会导致每个with 分支重复函数参数(一旦with 嵌套,情况会变得更糟),加上with 似乎无法播放使用隐式参数很好(但这本身可能值得提出一个问题)。
那么,为什么case 没有在这里提供帮助,除了纯粹的实现方式之外,还有其他原因与with 的行为不匹配吗?还有其他方法可以编写这个证明吗?
【问题讨论】:
标签: idris