在下面的代码中(这是试图解决“软件基础”中的一项练习),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
来避免这种行为?
我该如何简化/重写类型以取得进展?
答案 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