如何阅读GHC Core的“证明”?


84

我写了少量的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 }

我知道通过Flip类型家族的实例进行类型转换的一般流程,但是有些事情我无法完全理解:

  • 是什么意思@~ <Nat.Flip x_apH>_N?是x的Flip实例吗?@ (Nat.Flip x_apH)有何不同?我都有兴趣< >_N

关于第一个演员halve

  • 什么dt_dK6dt1_dK7dt2_dK8代表什么?我了解它们是某种等效证明,但是哪个是?
  • 我了解这Sym是通过向后等效实现的
  • 的作用是什么;?等价证明是按顺序应用的吗?
  • 这些是什么_N_R后缀?
  • TFCo:R:Flip[0]TFCo:R:Flip[1]Flip的实例吗?

6
我不知道,但我的猜测是,_N和_R的名义和代表角色:haskell.org/ghc/docs/latest/html/users_guide/...

Answers:


6

@~ 是强制性应用程序。

尖括号表示其所包含类型的反身强制性,其作用由下划线字母给出。

因此,这<Nat.Flip x_ap0H>_N是一个相等的证明,Nat.Flip x_apHNat.Flip x_apH名义上等于(作为相等的类型而不仅仅是相等的表示形式)。

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

我现在将完成类型的第一个转换 Nat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd

我们从开始(Nat.ParNat ...)_R。这是一个类型构造器应用程序。它提升的证明x_aIX ~# 'Nat.OddNat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd。这R意味着它具有代表性,意味着类型是同构的,但不相同(在这种情况下,它们是相同的,但是我们不需要该知识即可执行转换)。

现在我们来看证明的主体(dt1_dK7 ; (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N; Nat.TFCo:R:Flip[0]);表示暂时性,即按顺序应用这些证明。

dt1_dK7是的证明x_aIX ~# Nat.Flip y_aIY

如果我们看看(dt2_dK8 ; Sym dt_dK6)dt2_dK8显示y_aIY ~# Nat.Flip x_aIXdt_dK6是类型 'Nat.Even ~# Nat.Flip x_aIX。所以Sym dt_dK6是类型Nat.Flip x_aIX ~# 'Nat.Even(dt2_dK8 ; Sym dt_dK6)也是类型y_aIY ~# 'Nat.Even

由此(Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N证明Nat.Flip y_aIY ~# Nat.Flip 'Nat.Even

Nat.TFCo:R:Flip[0]是翻转的第一条规则 Nat.Flip 'Nat.Even ~# 'Nat.Odd'

将它们放在一起我们得到(dt1_dK7 ; (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N; Nat.TFCo:R:Flip[0])了type x_aIX #~ 'Nat.Odd

第二个更复杂的转换很难解决,但应该遵循相同的原理。


真的,我只是悬赏那个帖子,看看是否有人能理解这个烂摊子先生。
吉里·特雷卡克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.