मुझे हाल ही में पता चला है कि प्रूफ पर मिलान करने वाले पैटर्न के साथ संयुक्त प्रकार के छेद हास्केल में एक बहुत अच्छा एजडा जैसा अनुभव प्रदान करते हैं। उदाहरण के लिए:
{-# 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
एजडा के रूप में बहुत अधिक है ।
हालांकि, कभी-कभी छेद सिर्फ अपडेट करने में विफल रहता है:
(+.) :: 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...
इसके अलावा, भले ही लक्ष्य प्रकार आवश्यक रूप से प्रमाण के अंदर न हों, अगर मैं अगड़ा से पूरी चीज में पेस्ट करता हूं तो यह अभी भी ठीक जांचता है:
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
क्या आपके पास कोई विचार है कि ऐसा क्यों होता है (या मैं कैसे मजबूत तरीके से प्रूफ पुनर्लेखन कर सकता हूं)?
sym
कॉल को छोड़ सकते हैंmulDistL'
और आपका कोड अभी भी जाँच करेगा।