我最近发现,打样孔与样张上的图案匹配相结合,在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类型孔替换结构的右侧,并且我的孔目标类型使用证明进行了更新,这与rewriteAgda中的表格非常相似。
但是,有时漏洞只是无法更新:
(+.) :: 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ásKovács2014年
                    
                  
                
              
                  这与您的问题有点正交,但是您可以通过使用一组方程式推理组合器àla Agda来获得这些证明。cf. 这一概念证明
                
                
                  
                    —
                    盖瑞斯(Galais),
                    
                  
                
              
sym呼叫,mulDistL'而您的代码仍会检查。