Haskell 如何阅读本GHC核心文件“;证明;?

Haskell 如何阅读本GHC核心文件“;证明;?,haskell,ghc,proof,haskell-platform,formal-verification,Haskell,Ghc,Proof,Haskell Platform,Formal Verification,我写了这一小段Haskell来解释GHC如何证明自然数只能将偶数减半: {-# LANGUAGE DataKinds, GADTs, KindSignatures, TypeFamilies #-} module Nat where data Nat = Z | S Nat data Parity = Even | Odd type family Flip (x :: Parity) :: Parity where Flip Even = Odd Flip Odd = Even

我写了这一小段Haskell来解释GHC如何证明自然数只能将偶数减半:

{-# LANGUAGE DataKinds, GADTs, KindSignatures, TypeFamilies #-}
module Nat where

data Nat = Z | S Nat

data Parity = Even | Odd

type family Flip (x :: Parity) :: Parity where
  Flip Even = Odd
  Flip Odd  = Even

data ParNat :: Parity -> * where
  PZ :: ParNat Even
  PS :: (x ~ Flip y, y ~ Flip x) => ParNat x -> ParNat (Flip x)

halve :: ParNat Even -> Nat
halve PZ     = Z
halve (PS a) = helper a
  where helper :: ParNat Odd -> Nat
        helper (PS b) = S (halve b)
核心的相关部分变成:

Nat.$WPZ :: Nat.ParNat 'Nat.Even
Nat.$WPZ = Nat.PZ @ 'Nat.Even @~ <'Nat.Even>_N

Nat.$WPS
  :: forall (x_apH :: Nat.Parity) (y_apI :: Nat.Parity).
     (x_apH ~ Nat.Flip y_apI, y_apI ~ Nat.Flip x_apH) =>
     Nat.ParNat x_apH -> Nat.ParNat (Nat.Flip x_apH)
Nat.$WPS =
  \ (@ (x_apH :: Nat.Parity))
    (@ (y_apI :: Nat.Parity))
    (dt_aqR :: x_apH ~ Nat.Flip y_apI)
    (dt_aqS :: y_apI ~ Nat.Flip x_apH)
    (dt_aqT :: Nat.ParNat x_apH) ->
    case dt_aqR of _ { GHC.Types.Eq# dt_aqU ->
    case dt_aqS of _ { GHC.Types.Eq# dt_aqV ->
    Nat.PS
      @ (Nat.Flip x_apH)
      @ x_apH
      @ y_apI
      @~ <Nat.Flip x_apH>_N
      @~ dt_aqU
      @~ dt_aqV
      dt_aqT
    }
    }

Rec {
Nat.halve :: Nat.ParNat 'Nat.Even -> Nat.Nat
Nat.halve =
  \ (ds_dJB :: Nat.ParNat 'Nat.Even) ->
    case ds_dJB of _ {
      Nat.PZ dt_dKD -> Nat.Z;
      Nat.PS @ x_aIX @ y_aIY dt_dK6 dt1_dK7 dt2_dK8 a_apK ->
        case a_apK
             `cast` ((Nat.ParNat
                        (dt1_dK7
                         ; (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N
                         ; Nat.TFCo:R:Flip[0]))_R
                     :: Nat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd)
        of _
        { Nat.PS @ x1_aJ4 @ y1_aJ5 dt3_dKa dt4_dKb dt5_dKc b_apM ->
        Nat.S
          (Nat.halve
             (b_apM
              `cast` ((Nat.ParNat
                         (dt4_dKb
                          ; (Nat.Flip
                               (dt5_dKc
                                ; Sym dt3_dKa
                                ; Sym Nat.TFCo:R:Flip[0]
                                ; (Nat.Flip (dt_dK6 ; Sym dt2_dK8))_N
                                ; Sym dt1_dK7))_N
                          ; Sym dt_dK6))_R
                      :: Nat.ParNat x1_aJ4 ~# Nat.ParNat 'Nat.Even)))
        }
    }
end Rec }
Nat.$WPZ::Nat.ParNat'Nat.偶
Nat.$WPZ=Nat.PZ@'Nat.偶@~Nat.Nat
纳特:减半=
\(d_dJB::Nat.ParNat'Nat.Even)->
个案D_dJB of{
Nat.PZ dt_dKD->Nat.Z;
Nat.PS@x_aIX@y_aIY dt_dK6 dt1_dK7 dt2_dK8 a_apK->
案例a_apK
`演员`((Nat.ParNat)
(dt1_dK7)
(Nat.Flip(dt2_dK8;Sym dt_dK6))\N
;Nat.TFCo:R:Flip[0])\R
::Nat.ParNat x_aIX~#Nat.ParNat'Nat.Odd)
的_
{Nat.PS@x1_aJ4@y1_aJ5 dt3_dKa dt4_dKb dt5_dKc b_apM->
纳特
(自然减半
(b_apM)
`演员`((Nat.ParNat)
(dt4_dKb)
(纳特·弗利普)
(dt5_dKc)
;Sym dt3_dKa
;Sym Nat.TFCo:R:Flip[0]
(Nat.Flip(dt_dK6;Sym dt2_dK8))\N
;Sym dt1_dK7)_N
;Sym dt_dK6))\u R
::Nat.ParNat x1_aJ4~#Nat.ParNat'Nat.偶)
}
}
结束记录}
我知道通过翻转类型族的实例强制转换类型的一般流程,但有些事情我不能完全遵循:

  • @~\N
    的意思是什么?它是x的翻转实例吗?这与
    @(Nat.Flip x_apH)
    有何不同?我对
    \N
    都感兴趣
关于第一次铸入
减半

  • dt_dK6
    dt1_dK7
    dt2_dK8
    代表什么?我知道它们是某种等价证明,但哪一种是哪一种
  • 我知道
    Sym
    是通过一个等价关系运行的
  • 什么是
    
    
  • 这些后缀是什么
  • TFCo:R:Flip[0]
    TFCo:R:Flip[1]
    是Flip的实例吗

@
是强制应用程序

尖括号表示其包含类型的反身强制,角色由带下划线的字母给出

因此,
\N
是一个等式证明,
Nat.Flip x_apH
名义上等于
Nat.Flip x_apH
(作为相等的类型,而不仅仅是相等的表示)

PS有很多论点。我们查看智能构造函数
$WPS
,我们可以看到前两个分别是x和y的类型。我们有证据证明构造函数参数是
Flip x
(在这种情况下,我们有
Flip x~偶数
。然后我们有证据
x~ Flip y
y~ Flip x
。最后一个参数是
ParNat x
的值

现在,我将介绍类型
Nat.ParNat x_aIX~#Nat.ParNat'Nat.Odd的第一次转换

我们从
(Nat.ParNat…)(在这种情况下,它们是相同的,但我们不需要这些知识来执行演员阵容)

现在我们来看一下证明的主体(dt1\u dK7;(Nat.Flip(dt2\u dK8;Sym dt\u dK6))\N;Nat.TFCo:R:Flip[0])
意味着传递,即按顺序应用这些证明

dt1_dK7
x#u aIX~#Nat.Flip y_aIY
的证明

如果我们看一下
(dt2_dK8;Sym dt_dK6)
dt2_dK8
显示
y#aIY#Nat.Flip x#aIX
dt#dK6
属于
类型的Nat.偶#Nat Nat
的类型为
y#aIY##Nat.偶数

因此,
(Nat.Flip(dt2_dK8;Sym dt_dK6))\N
证明了
Nat.Flip y#aIY~#Nat.Flip'Nat.Even

Nat.TFCo:R:Flip[0]
是Flip的第一条规则,即
Nat.Flip'Nat.偶~#'Nat.Odd'

把它们放在一起,我们得到了
(dt1_dK7;(Nat.Flip(dt2_dK8;Sym dt_dK6))\N;Nat.TFCo:R:Flip[0])
的类型是
x#aIX ~'Nat Odd


第二个更复杂的角色有点难演,但应该遵循同样的原则。

我不知道,但我猜_N和_R是象征性和代表性的角色:访问希望你有想法。。真的,我刚刚发了那篇帖子,想看看是否有人能理解那团混乱。^干得好,先生。