최근에 증명에서 패턴 매칭과 결합 된 타입 홀이 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
구조 의 오른쪽을 유형 구멍 으로 대체 할 수 있고 구멍 대상 유형이 rewrite
Agda 의 양식 과 거의 비슷하게 증명으로 업데이트된다는 것 입니다.
그러나 때때로 구멍이 업데이트되지 않습니다.
(+.) :: 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
왜 이런 일이 발생하는지 (또는 어떻게 확실한 방법으로 증명 재 작성을 할 수 있는지) 아이디어가 있습니까?
아마도 나는 너무 많은 것을 기대하고 있습니다. 그러나 대부분의 경우 Agda에서와 같이 작동하므로 동작의 규칙 성을 파악하는 것이 여전히 유용합니다. 문제가 유형 검사기의 장과 깊이 관련되어 있기 때문에 나는 낙관적이지 않습니다.
—
András Kovács 2014
sym
호출을 생략 할 수mulDistL'
있으며 코드는 계속 확인합니다.