有没有办法重写和简化 `decEq x x`?
is there a way to rewrite and simplify `decEq x x`?
在以下代码中(这是尝试解决 'Software Foundations' [列表章节] 中的练习),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
来避免这种行为?
我可以对 simplify/rewrite 类型做些什么才能取得进展?
你的计数函数比它需要的更分裂。如果您仍然检查 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
的straight-forward方法就是顺其自然。你的 countSingleton_rhs
有一个复杂的类型,因为类型是 case switch,取决于 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
类型并不总是有效。但是你可以用 with
重写 count
来规避这个问题:
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
在以下代码中(这是尝试解决 'Software Foundations' [列表章节] 中的练习),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
来避免这种行为?
我可以对 simplify/rewrite 类型做些什么才能取得进展?
你的计数函数比它需要的更分裂。如果您仍然检查 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
的straight-forward方法就是顺其自然。你的 countSingleton_rhs
有一个复杂的类型,因为类型是 case switch,取决于 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
类型并不总是有效。但是你可以用 with
重写 count
来规避这个问题:
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