用案例

时间:2018-05-01 17:40:57

标签: idris

我们假设我们有一个函数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_1wut_2的类型与merge的案例表达式的相应分支相匹配似乎是合理的(因此wut_1将是像NonEmpty (x :: merge f xs (y :: ys))这样的东西,可以立即得到满足),但我们的希望失败了:类型与原始wut的类型相同。

确实,唯一的方法似乎是使用with - 子句:

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的行为相匹配,还有其他方法可以写这个证据?

2 个答案:

答案 0 :(得分:2)

只有当新信息以某种方式向后传播到参数时,才需要|左边的内容。

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) with (x `f` y)
  | True = IsNonEmpty
  | False = IsNonEmpty

-- for contrast
sym' : (() -> x = y) -> y = x
sym' {x} {y} prf with (prf ())
-- matching against Refl needs x and y to be the same
-- now we need to write out the full form
  sym' {x} {y=x} prf | Refl = Refl

至于为什么就是这种情况,我确实认为这只是实施,但是知道更好的人可能会对此提出质疑。

答案 1 :(得分:2)

关于使用case证明事情的问题:https://github.com/idris-lang/Idris-dev/issues/4001

因此,在idris-bi中,我们最终必须删除此类函数中的所有case并定义与案例条件匹配的单独顶级助手,例如here