[英]How to read this GHC Core “proof”?
I wrote this small bit of Haskell to figure out how GHC proves that for natural numbers, you can only halve the even ones: 我写了一小部分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)
The relevant parts of core become: 核心的相关部分变为:
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 }
I know the general flow of casting the types through instances of the Flip type family, but there are some things that I cannot completely follow: 我知道通过Flip类型系列的实例来转换类型的一般流程,但有些事情我无法完全遵循:
@~ <Nat.Flip x_apH>_N
? @~ <Nat.Flip x_apH>_N
是什么意思? is it the Flip instance for x? @ (Nat.Flip x_apH)
? @ (Nat.Flip x_apH)
什么不同? I'm both interested in < >
and _N
< >
和_N
感兴趣 Regarding the first cast in halve
: 对于一次投
halve
:
dt_dK6
, dt1_dK7
and dt2_dK8
stand for? dt_dK6
, dt1_dK7
和dt2_dK8
代表什么? I understand they are some kind of equivalence proofs, but which is which? Sym
runs through an equivalence backwards Sym
向后运行等价 ;
;
's do? _N
and _R
suffixes? _N
和_R
后缀是什么? TFCo:R:Flip[0]
and TFCo:R:Flip[1]
the instances of Flip? TFCo:R:Flip[0]
和TFCo:R:Flip[1]
Flip的实例? @~
is coercion application. @~
是胁迫申请。
The angle brackets denote a reflexive coercion of their contained type with role given by the underscored letter. 尖括号表示其所包含类型的反身强制与强调字母给出的作用。
Thus <Nat.Flip x_ap0H>_N
is an equality proof that Nat.Flip x_apH
is equal to Nat.Flip x_apH
nominally (as equal types not just equal representations). 因此
<Nat.Flip x_ap0H>_N
是相等证明Nat.Flip x_apH
等于Nat.Flip x_apH
名义上(如等于类型不恰好等于表示)。
PS has a lot of arguments. PS有很多争论。 We look at the smart constructor
$WPS
and we can see the first two are the types of x and y respectively. 我们看一下智能构造函数
$WPS
,我们可以看到前两个分别是x和y的类型。 We have proof that the constructor argument is Flip x
(in this case we have Flip x ~ Even
. We then have the proofs x ~ Flip y
and y ~ Flip x
. The final argument is a value of ParNat x
. 我们已经证明构造函数参数是
Flip x
(在这种情况下我们有Flip x ~ Even
。然后我们有证明x ~ Flip y
和y ~ Flip x
。最后一个参数是ParNat x
的值。
I will now walk through the first cast of type Nat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd
我现在将介绍
Nat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd
类型的第一个演员Nat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd
We start with (Nat.ParNat ...)_R
. 我们从
(Nat.ParNat ...)_R
。 This is a type constructor application. 这是一个类型构造函数应用程序。 It lifts the proof of
x_aIX ~# 'Nat.Odd
to Nat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd
. 它将
x_aIX ~# 'Nat.Odd
的证明x_aIX ~# 'Nat.Odd
为Nat.ParNat x_aIX ~# Nat.ParNat 'Nat.Odd
。 The R
means it does this representationally meaning that the types are isomorphic but not the same (in this case they are the same but we don't need that knowledge to perform the cast). R
意味着它表示这意味着类型是同构的但不相同(在这种情况下它们是相同的但我们不需要那些知识来执行演员表)。
Now we look at main body of the proof (dt1_dK7 ; (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N; Nat.TFCo:R:Flip[0])
. 现在我们看一下证明的主体
(dt1_dK7 ; (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N; Nat.TFCo:R:Flip[0])
。 ;
means transitivty ie apply these proofs in order. 意味着过渡,即按顺序应用这些证明。
dt1_dK7
is a proof of x_aIX ~# Nat.Flip y_aIY
. dt1_dK7
是x_aIX ~# Nat.Flip y_aIY
的证明。
If we look at (dt2_dK8 ; Sym dt_dK6)
. 如果我们看
(dt2_dK8 ; Sym dt_dK6)
。 dt2_dK8
shows y_aIY ~# Nat.Flip x_aIX
. dt2_dK8
显示y_aIY ~# Nat.Flip x_aIX
。 dt_dK6
is of type 'Nat.Even ~# Nat.Flip x_aIX
. dt_dK6
的类型为'Nat.Even ~# Nat.Flip x_aIX
。 So Sym dt_dK6
is of type Nat.Flip x_aIX ~# 'Nat.Even
and (dt2_dK8 ; Sym dt_dK6)
is of type y_aIY ~# 'Nat.Even
所以
Sym dt_dK6
属于Sym dt_dK6
类型Nat.Flip x_aIX ~# 'Nat.Even
和(dt2_dK8 ; Sym dt_dK6)
类型为y_aIY ~# 'Nat.Even
Thus (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N
is a proof that Nat.Flip y_aIY ~# Nat.Flip 'Nat.Even
. 因此
(Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N
是Nat.Flip y_aIY ~# Nat.Flip 'Nat.Even
。
Nat.TFCo:R:Flip[0]
is the first rule of flip which is Nat.Flip 'Nat.Even ~# 'Nat.Odd'
. Nat.TFCo:R:Flip[0]
是翻转的第一个规则,即Nat.Flip 'Nat.Even ~# 'Nat.Odd'
。
Putting these together we get (dt1_dK7 ; (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N; Nat.TFCo:R:Flip[0])
has type x_aIX #~ 'Nat.Odd
. 将这些放在一起我们得到
(dt1_dK7 ; (Nat.Flip (dt2_dK8 ; Sym dt_dK6))_N; Nat.TFCo:R:Flip[0])
具有类型x_aIX #~ 'Nat.Odd
。
The second more complicated cast is a bit harder to work out but should work on the same principle. 第二个更复杂的演员阵容有点难以解决,但应该按照相同的原则工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.