Come leggere questa "prova" di GHC Core?


84

Ho scritto questo piccolo pezzo di Haskell per capire come GHC dimostra che per i numeri naturali, puoi solo dimezzare quelli pari:

{-# 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)

Le parti rilevanti del core diventano:

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 }

Conosco il flusso generale di casting dei tipi attraverso istanze della famiglia di tipi Flip, ma ci sono alcune cose che non posso seguire completamente:

  • Qual è il significato di @~ <Nat.Flip x_apH>_N? è l'istanza Flip per x? In che cosa differisce @ (Nat.Flip x_apH)? Sono entrambi interessati a < >e_N

Per quanto riguarda il primo cast in halve:

  • Cosa fare dt_dK6, dt1_dK7e dt2_dK8stand for? Capisco che siano una sorta di prove di equivalenza, ma quale è quale?
  • Capisco che Sympassa attraverso un'equivalenza all'indietro
  • Cosa ;fanno? Le prove di equivalenza sono applicate solo in sequenza?
  • Cosa sono questi _Ne i _Rsuffissi?
  • Sono TFCo:R:Flip[0]e TFCo:R:Flip[1]le istanze di Flip?

6
Non ne ho idea, ma la mia ipotesi è che _N e _R siano i ruoli nominali e rappresentativi: haskell.org/ghc/docs/latest/html/users_guide/…
chi

Risposte:


6

@~ è un'applicazione di coercizione.

Le parentesi angolari denotano una coercizione riflessiva del loro tipo contenuto con ruolo dato dalla lettera sottolineata.

Quindi <Nat.Flip x_ap0H>_Nè una prova di uguaglianza che Nat.Flip x_apHè uguale a Nat.Flip x_apHnominalmente (come tipi uguali non solo rappresentazioni uguali).

PS ha molti argomenti. Guardiamo il costruttore intelligente $WPSe possiamo vedere che i primi due sono i tipi di x e y rispettivamente. Abbiamo la prova che l'argomento del costruttore è Flip x(in questo caso abbiamo Flip x ~ Even. Abbiamo quindi le dimostrazionix ~ Flip y e y ~ Flip x. L'argomento finale è un valore di ParNat x.

Passerò ora attraverso il primo cast di caratteri Nat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd

Cominciamo con (Nat.ParNat ...)_R. Questa è un'applicazione di costruzione del tipo. Solleva la prova di x_aIX ~# 'Nat.OddaNat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd . Il Rmezzo lo fa rappresentazionalmente, il che significa che i tipi sono isomorfi ma non uguali (in questo caso sono gli stessi ma non abbiamo bisogno di quella conoscenza per eseguire il cast).

Ora esaminiamo il corpo principale della dimostrazione (dt1_dK7 ; (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N; Nat.TFCo:R:Flip[0]) . ;significa transitività cioè applica queste prove in ordine.

dt1_dK7 è una prova di x_aIX ~# Nat.Flip y_aIY .

Se guardiamo (dt2_dK8 ; Sym dt_dK6). dt2_dK8spettacoli y_aIY ~# Nat.Flip x_aIX. dt_dK6è di tipo 'Nat.Even ~# Nat.Flip x_aIX. Quindi Sym dt_dK6è di tipoNat.Flip x_aIX ~# 'Nat.Even ed (dt2_dK8 ; Sym dt_dK6)è di tipoy_aIY ~# 'Nat.Even

Così (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N è una prova che Nat.Flip y_aIY ~# Nat.Flip 'Nat.Even.

Nat.TFCo:R:Flip[0] è la prima regola del flip che è Nat.Flip 'Nat.Even ~# 'Nat.Odd' .

Mettendoli insieme otteniamo (dt1_dK7 ; (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N; Nat.TFCo:R:Flip[0]) tipo x_aIX #~ 'Nat.Odd.

Il secondo cast più complicato è un po 'più difficile da elaborare ma dovrebbe funzionare sullo stesso principio.


Davvero ho solo abbellito quel post per vedere se qualcuno riesce a dare un senso a quel casino ^^ bravo signore.
Jiri Trecak
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.