有没有办法重写和简化`decEq x x`?

时间:2019-07-16 07:26:59

标签: idris

在下面的代码中(这是试图解决“软件基础”中的一项练习),Idris报告了countSingleton_rhs的非常复杂的类型。该类型包括一个复杂表达式,其核心是以下内容:case decEq x x of ...

module CountSingleton

data NatList : Type where
  Nil : NatList
  (::) : Nat -> NatList -> NatList

-- count occurrences of a value in a list
count : (v : Nat) -> (s : NatList) -> Nat
count _ [] = Z
count Z (Z :: ns) = S (count Z ns)
count Z (_ :: ns) = count Z ns
count j@(S _) (Z :: ns) = count j ns
count (S j) ((S k) :: ns) =
  case decEq j k of
    Yes Refl => S (count (S j) ns)
    No _ => count (S j) ns

-- to prove
countSingleton : (v : Nat) -> (count v [v]) = S Z
countSingleton Z = Refl
countSingleton (S k) = ?countSingleton_rhs

为什么Idris不将decEq x x简化为Yes Refl? 有没有更好的方法来实现count来避免这种行为? 我该如何简化/重写类型以取得进展?

1 个答案:

答案 0 :(得分:1)

您的计数功能超出了需要的范围。如果仍然检查decEq x y,则可以统一除count _ [] = Z以外的所有情况:

count : (v : Nat) -> (s : NatList) -> Nat
count _ [] = Z
count x (y :: ns) = case decEq x y of
    Yes Refl => S (count x ns)
    No _ => count x ns

证明countSingleton的直接方法是遵循流程。您的countSingleton_rhs具有复杂的类型,因为该类型是大小写转换,取决于decEq v v的结果。使用with Idris可以将分支结果应用于结果类型。

countSingleton : (v : Nat) -> (count v [v]) = S Z
countSingleton v with (decEq v v)
    | Yes prf = Refl
    | No contra = absurd $ contra Refl

您已经注意到,这似乎有点多余,因为decEq x x很明显是Yes Refl。幸运的是,它已经在库decEqSelfIsYes : DecEq a => decEq x x = Yes Refl中得到证明,我们可以使用它来重写结果类型:

countSingleton : (v : Nat) -> (count v [v]) = S Z
countSingleton v = rewrite decEqSelfIsYes {x=v} in Refl

不幸的是,由于an open issue,重写case类型并不总是有效。但是您可以使用count重写with来解决此问题:

count : (v : Nat) -> (s : NatList) -> Nat
count _ [] = Z
count x (y :: ns) with (decEq x y)
    | Yes _ = S (count x ns)
    | No _ = count x ns