Як прочитати цей «доказ» Ядра GHC?


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? це екземпляр Flip для x? Чим це відрізняється від @ (Nat.Flip x_apH)? Мене одночасно цікавить < >і_N

Щодо першого акторського складу halve:

  • Що dt_dK6, dt1_dK7і на dt2_dK8стенді? Я розумію, що вони є певними доказами еквівалентності, але що це таке?
  • Я розумію, що це Symпроходить через еквівалентність назад
  • Що ;роблять? Чи просто застосовуються докази еквівалентності послідовно?
  • Що це _Nі _Rсуфікси?
  • Є TFCo:R:Flip[0]і TFCo:R:Flip[1]екземпляри Flip?

6
Я не маю уявлення, але я здогадуюсь, що _N та _R - це іменна та представницька ролі: haskell.org/ghc/docs/latest/html/users_guide/…
chi

Відвідайте stackoverflow.com/questions/6121146/reading-ghc-core сподіваємось, ви зрозуміли ..
Hemant Ramphul

Відповіді:


6

@~ є застосування примусу.

Кутові дужки позначають рефлексивний примус їх вміщеного типу з роллю, відведеною підкресленою буквою.

Таким чином, <Nat.Flip x_ap0H>_Nє доказом рівності, який Nat.Flip x_apHдорівнює Nat.Flip x_apHномінально (як рівні типи, а не просто рівні уявлення).

PS має багато аргументів. Ми розглядаємо розумний конструктор $WPSі бачимо, що перші два - це типи x та y відповідно. У нас є доказ того, що аргументом конструктора є Flip x(у цьому випадку ми маємо Flip x ~ Even. Тоді ми маємо докази x ~ Flip yі y ~ Flip x. Кінцевим аргументом є значення ParNat x.

Зараз я пройдусь по першому акторському складу Nat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd

Починаємо з (Nat.ParNat ...)_R. Це програма конструктора типів. Він піднімає доказ x_aIX ~# 'Nat.Oddдо Nat.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_aIX. dt_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])тип x_aIX #~ 'Nat.Odd.

Другий складніший акторський склад трохи складніше опрацювати, але він повинен працювати за тим же принципом.


Дійсно, я просто поблагодарив за цю посаду, щоб побачити, чи хтось може зрозуміти цей безлад ^^ молодець, сер.
Іржі Тречак
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.