【发布时间】:2014-03-31 17:29:13
【问题描述】:
我最近发现,在证明中结合使用模式匹配的类型孔在 Haskell 中提供了非常好的类似 Agda 的体验。例如:
{-# LANGUAGE
DataKinds, PolyKinds, TypeFamilies,
UndecidableInstances, GADTs, TypeOperators #-}
data (==) :: k -> k -> * where
Refl :: x == x
sym :: a == b -> b == a
sym Refl = Refl
data Nat = Zero | Succ Nat
data SNat :: Nat -> * where
SZero :: SNat Zero
SSucc :: SNat n -> SNat (Succ n)
type family a + b where
Zero + b = b
Succ a + b = Succ (a + b)
addAssoc :: SNat a -> SNat b -> SNat c -> (a + (b + c)) == ((a + b) + c)
addAssoc SZero b c = Refl
addAssoc (SSucc a) b c = case addAssoc a b c of Refl -> Refl
addComm :: SNat a -> SNat b -> (a + b) == (b + a)
addComm SZero SZero = Refl
addComm (SSucc a) SZero = case addComm a SZero of Refl -> Refl
addComm SZero (SSucc b) = case addComm SZero b of Refl -> Refl
addComm sa@(SSucc a) sb@(SSucc b) =
case addComm a sb of
Refl -> case addComm b sa of
Refl -> case addComm a b of
Refl -> Refl
真正的好处是我可以用类型孔替换Refl -> exp 结构的右侧,并且我的孔目标类型会随着证明进行更新,与Agda 中的rewrite 形式非常相似.
但是,有时洞只是无法更新:
(+.) :: SNat a -> SNat b -> SNat (a + b)
SZero +. b = b
SSucc a +. b = SSucc (a +. b)
infixl 5 +.
type family a * b where
Zero * b = Zero
Succ a * b = b + (a * b)
(*.) :: SNat a -> SNat b -> SNat (a * b)
SZero *. b = SZero
SSucc a *. b = b +. (a *. b)
infixl 6 *.
mulDistL :: SNat a -> SNat b -> SNat c -> (a * (b + c)) == ((a * b) + (a * c))
mulDistL SZero b c = Refl
mulDistL (SSucc a) b c =
case sym $ addAssoc b (a *. b) (c +. a *. c) of
-- At this point the target type is
-- ((b + c) + (n * (b + c))) == (b + ((n * b) + (c + (n * c))))
-- The next step would be to update the RHS of the equivalence:
Refl -> case addAssoc (a *. b) c (a *. c) of
Refl -> _ -- but the type of this hole remains unchanged...
此外,即使目标类型不一定在证明中排列,如果我从 Agda 粘贴整个内容,它仍然可以检查:
mulDistL' :: SNat a -> SNat b -> SNat c -> (a * (b + c)) == ((a * b) + (a * c))
mulDistL' SZero b c = Refl
mulDistL' (SSucc a) b c = case
(sym $ addAssoc b (a *. b) (c +. a *. c),
addAssoc (a *. b) c (a *. c),
addComm (a *. b) c,
sym $ addAssoc c (a *. b) (a *. c),
addAssoc b c (a *. b +. a *. c),
mulDistL' a b c
) of (Refl, Refl, Refl, Refl, Refl, Refl) -> Refl
您对为什么会发生这种情况有任何想法(或者我如何以稳健的方式进行证明重写)?
【问题讨论】:
-
你是不是有点期待?等式证明上的模式匹配正在建立(双向)等式。完全不清楚您希望将其应用于目标类型的位置和方向。例如,您可以省略
mulDistL'中的sym调用,您的代码仍会检查。 -
很可能我期待太多了。但是,在许多情况下,它确实像在 Agda 中一样工作,因此找出行为的规律性仍然很有用。不过我并不乐观,因为这件事很可能与类型检查器有关。
-
这与您的问题有点正交,但您可以通过使用一组方程式推理组合器 à la Agda 来完成这些证明。参照。 this proof of concept