ดังนั้นฉันจึงคิดเกี่ยวกับมันอีกเล็กน้อยและก้าวหน้า นี่เป็นการแทงครั้งแรกในการเข้ารหัสระบบที่เรียบง่าย (แต่ไม่สอดคล้องกัน) ของ Martin-Löf Set : Set
ในรูปแบบผสมผสาน ไม่ใช่วิธีที่ดีที่จะทำให้เสร็จ แต่เป็นจุดเริ่มต้นที่ง่ายที่สุด ไวยากรณ์ของทฤษฎีประเภทนี้เป็นเพียงแลมด้า - แคลคูลัสที่มีคำอธิบายประกอบประเภท Pi-types และชุดจักรวาล
ทฤษฎีประเภทเป้าหมาย
เพื่อความสมบูรณ์ฉันจะนำเสนอกฎ บริบทความถูกต้องเพียงแค่บอกว่าคุณสามารถสร้างบริบทจากว่างเปล่าโดยการติดตัวแปรสดพำนักSet
s
G |- valid G |- S : Set
. |- valid G, x:S |- valid
และตอนนี้เราสามารถพูดได้ว่าจะสังเคราะห์ประเภทของคำศัพท์ในบริบทใด ๆ ได้อย่างไรและจะเปลี่ยนประเภทของบางสิ่งตามพฤติกรรมการคำนวณของคำศัพท์ที่มีอยู่ได้อย่างไร
G |- valid G |- S : Set G |- T : Pi S \ x:S -> Set
G |- Set : Set G |- Pi S T : Set
G |- S : Set G, x:S |- t : T x G |- f : Pi S T G |- s : S
G |- \ x:S -> t : Pi S T G |- f s : T s
G |- valid G |- s : S G |- T : Set
G |- x : S G |- s : T
ในรูปแบบเล็ก ๆ น้อย ๆ จากต้นฉบับฉันได้กำหนดให้แลมบ์ดาเป็นตัวดำเนินการผูกพันเพียงตัวเดียวดังนั้นอาร์กิวเมนต์ที่สองของ Pi ควรเป็นฟังก์ชันที่คำนวณวิธีที่ประเภทผลตอบแทนขึ้นอยู่กับอินพุต ตามแบบแผน (เช่นใน Agda แต่น่าเศร้าที่ไม่ได้อยู่ใน Haskell) ขอบเขตของ lambda จะขยายไปทางขวาให้มากที่สุดดังนั้นคุณมักจะปล่อยให้ abstractions ไม่ติดเครื่องหมายเมื่อเป็นอาร์กิวเมนต์สุดท้ายของตัวดำเนินการลำดับที่สูงกว่า: คุณจะเห็นว่าฉันทำ กับ Pi ประเภท AGDA ของคุณจะกลายเป็น(x : S) -> T
Pi S \ x:S -> T
( Digressionคำอธิบายประกอบประเภทบนแลมบ์ดาเป็นสิ่งที่จำเป็นหากคุณต้องการสังเคราะห์ประเภทของ abstractions หากคุณเปลี่ยนไปใช้การพิมพ์การตรวจสอบเป็นตัวดำเนินการตามวิธีการของคุณคุณยังคงต้องใช้คำอธิบายประกอบเพื่อตรวจสอบเบต้า - เรดเอ็กซ์เช่นเดียว(\ x -> t) s
กับที่คุณไม่มีทาง เพื่อคาดเดาประเภทของชิ้นส่วนจากทั้งหมดนั้นฉันแนะนำให้นักออกแบบสมัยใหม่ตรวจสอบประเภทและแยก beta-redxes ออกจากไวยากรณ์)
( Digressionระบบนี้ไม่สอดคล้องกันเนื่องจากSet:Set
อนุญาตให้เข้ารหัส "คนโกหก" ที่หลากหลายเมื่อ Martin-Löfเสนอทฤษฎีนี้ Girard ส่งการเข้ารหัสให้เขาในระบบ U ที่ไม่สอดคล้องกันของตัวเองความขัดแย้งที่ตามมาเนื่องจาก Hurkens คือ โครงสร้างที่เป็นพิษที่บริสุทธิ์ที่สุดที่เรารู้จัก)
Combinator Syntax และ Normalization
อย่างไรก็ตามเรามีสัญลักษณ์พิเศษสองตัวคือ Pi และ Set ดังนั้นเราอาจจัดการการแปลแบบผสมด้วย S, K และสัญลักษณ์พิเศษสองตัว: ฉันเลือก U สำหรับจักรวาลและ P สำหรับผลิตภัณฑ์
ตอนนี้เราสามารถกำหนดไวยากรณ์รวมที่ไม่ได้พิมพ์ (พร้อมตัวแปรอิสระ):
data SKUP = S | K | U | P deriving (Show, Eq)
data Unty a
= C SKUP
| Unty a :. Unty a
| V a
deriving (Functor, Eq)
infixl 4 :.
โปรดทราบว่าฉันได้รวมวิธีการรวมตัวแปรอิสระที่แสดงตามประเภทa
ในไวยากรณ์นี้ นอกเหนือจากการเป็นรีเฟล็กซ์ในส่วนของฉัน (ทุกไวยากรณ์ที่คู่ควรกับชื่อคือ monad ฟรีที่มีreturn
ตัวแปรฝังและการ>>=
แทนที่แบบเพอร์เฟกต์) มันจะมีประโยชน์ในการแสดงขั้นตอนกลางในกระบวนการแปลงคำที่มีผลผูกพันกับรูปแบบผสม
นี่คือการทำให้เป็นมาตรฐาน:
norm :: Unty a -> Unty a
norm (f :. a) = norm f $. a
norm c = c
($.) :: Unty a -> Unty a -> Unty a
C S :. f :. a $. g = f $. g $. (a :. g)
C K :. a $. g = a
n $. g = n :. norm g
infixl 4 $.
(แบบฝึกหัดสำหรับผู้อ่านคือการกำหนดประเภทของรูปแบบปกติและเพิ่มความคมชัดของประเภทของการดำเนินการเหล่านี้)
เป็นตัวแทนของทฤษฎีประเภท
ตอนนี้เราสามารถกำหนดไวยากรณ์สำหรับทฤษฎีประเภทของเราได้แล้ว
data Tm a
= Var a
| Lam (Tm a) (Tm (Su a))
| Tm a :$ Tm a
| Pi (Tm a) (Tm a)
| Set
deriving (Show, Functor)
infixl 4 :$
data Ze
magic :: Ze -> a
magic x = x `seq` error "Tragic!"
data Su a = Ze | Su a deriving (Show, Functor, Eq)
ฉันใช้การแสดงดัชนี de Bruijn ในลักษณะ Bellegarde และ Hook (ดังที่ Bird and Paterson เป็นที่นิยม) ชนิดที่Su a
มีอีกหนึ่งองค์ประกอบกว่าa
และเราจะใช้มันเป็นชนิดของตัวแปรอิสระภายใต้การยึดเกาะกับZe
เป็นตัวแปรที่ถูกผูกไว้ใหม่และเป็นตัวแทนขยับของตัวแปรอิสระที่เก่าSu x
x
การแปลข้อกำหนดเป็น Combinators
และมีที่ทำเราได้รับการแปลปกติขึ้นอยู่กับวงเล็บนามธรรม
tm :: Tm a -> Unty a
tm (Var a) = V a
tm (Lam _ b) = bra (tm b)
tm (f :$ a) = tm f :. tm a
tm (Pi a b) = C P :. tm a :. tm b
tm Set = C U
bra :: Unty (Su a) -> Unty a
bra (V Ze) = C S :. C K :. C K
bra (V (Su x)) = C K :. V x
bra (C c) = C K :. C c
bra (f :. a) = C S :. bra f :. bra a
การพิมพ์ Combinators
การแปลแสดงให้เห็นถึงวิธีที่เราใช้ตัวผสมซึ่งทำให้เราได้เบาะแสว่าควรจะเป็นประเภทใด U
และP
เป็นเพียงตัวสร้างที่ตั้งค่าไว้ดังนั้นการเขียนประเภทที่ไม่ได้แปลและอนุญาต "สัญกรณ์ Agda" สำหรับ Pi เราควรมี
U : Set
P : (A : Set) -> (B : (a : A) -> Set) -> Set
K
Combinator จะใช้ในการยกค่าของบางชนิดกับฟังก์ชั่นอย่างต่อเนื่องกว่าชนิดอื่นA
ๆG
G : Set A : Set
K : (a : A) -> (g : G) -> A
S
Combinator ถูกนำมาใช้เพื่อการใช้งานลิฟท์มากกว่าประเภทตามที่ทุกชิ้นส่วนอาจขึ้นอยู่
G : Set
A : (g : G) -> Set
B : (g : G) -> (a : A g) -> Set
S : (f : (g : G) -> (a : A g) -> B g a ) ->
(a : (g : G) -> A g ) ->
(g : G) -> B g (a g)
หากคุณดูประเภทของS
คุณจะเห็นว่ามันระบุกฎแอ็พพลิเคชันตามบริบทของทฤษฎีประเภทดังนั้นนั่นคือสิ่งที่เหมาะสมที่จะสะท้อนโครงสร้างแอปพลิเคชัน นั่นคืองาน!
จากนั้นเรามีแอปพลิเคชันสำหรับสิ่งที่ปิดเท่านั้น
f : Pi A B
a : A
f a : B a
แต่มีอุปสรรค์ ฉันได้เขียนประเภทของ Combinators ในทฤษฎีประเภทธรรมดาไม่ใช่ทฤษฎีประเภท Combinatory โชคดีที่ฉันมีเครื่องที่จะทำการแปล
ระบบ Combinatory Type
U : U
P : PU(S(S(KP)(S(S(KP)(SKK))(S(KK)(KU))))(S(KK)(KU)))
G : U
A : U
K : P[A](S(S(KP)(K[G]))(S(KK)(K[A])))
G : U
A : P[G](KU)
B : P[G](S(S(KP)(S(K[A])(SKK)))(S(KK)(KU)))
S : P(P[G](S(S(KP)(S(K[A])(SKK)))(S(S(KS)(S(S(KS)(S(KK)(K[B])))(S(KK)(SKK))))
(S(S(KS)(KK))(KK)))))(S(S(KP)(S(S(KP)(K[G]))(S(S(KS)(S(KK)(K[A])))
(S(S(KS)(KK))(KK)))))(S(S(KS)(S(S(KS)(S(KK)(KP)))(S(KK)(K[G]))))
(S(S(KS)(S(S(KS)(S(KK)(KS)))(S(S(KS)(S(S(KS)(S(KK)(KS)))
(S(S(KS)(S(KK)(KK)))(S(KK)(K[B])))))(S(S(KS)(S(S(KS)(S(KK)(KS)))(S(KK)(KK))))
(S(KK)(KK))))))(S(S(KS)(S(S(KS)(S(KK)(KS)))(S(S(KS)(S(KK)(KK)))
(S(S(KS)(KK))(KK)))))(S(S(KS)(S(S(KS)(S(KK)(KS)))(S(KK)(KK))))(S(KK)(KK)))))))
M : A B : U
M : B
ดังนั้นคุณจึงมีมันในรัศมีภาพที่อ่านไม่ออกทั้งหมด: การนำเสนอแบบผสมผสานSet:Set
!
ยังมีปัญหาเล็กน้อย ไวยากรณ์ของระบบช่วยให้คุณมีวิธีการที่จะคาดเดาไม่G
, A
และB
พารามิเตอร์สำหรับการS
และในทำนองเดียวกันสำหรับK
เพียงจากคำว่า ในทำนองเดียวกันเราสามารถตรวจสอบการได้มาจากการพิมพ์โดยใช้อัลกอริทึม แต่เราไม่สามารถตรวจสอบคำที่ใช้ร่วมกันได้อย่างที่ทำได้กับระบบเดิม สิ่งที่อาจได้ผลคือต้องการให้อินพุตไปยังตัวตรวจสอบตัวพิมพ์เพื่อรองรับคำอธิบายประกอบเกี่ยวกับการใช้ S และ K บันทึกการได้มาอย่างมีประสิทธิภาพ แต่นั่นคือหนอนอีกกระป๋อง ...
นี่เป็นสถานที่ที่ดีที่จะหยุดหากคุณกระตือรือร้นที่จะเริ่มต้น ส่วนที่เหลือคือ "เบื้องหลัง"
การสร้างประเภทของ Combinators
ฉันสร้างประเภทรวมกันเหล่านั้นโดยใช้การแปลสิ่งที่เป็นนามธรรมของวงเล็บจากข้อกำหนดทฤษฎีประเภทที่เกี่ยวข้อง เพื่อแสดงให้เห็นว่าฉันทำได้อย่างไรและทำให้โพสต์นี้ไม่ไร้จุดหมายโดยสิ้นเชิงให้ฉันเสนออุปกรณ์ของฉัน
ฉันสามารถเขียนประเภทของตัวผสมโดยสรุปไว้เหนือพารามิเตอร์ของมันได้ดังนี้ ฉันใช้ประโยชน์จากpil
ฟังก์ชันที่มีประโยชน์ของฉันซึ่งรวม Pi และแลมบ์ดาเพื่อหลีกเลี่ยงการทำซ้ำประเภทโดเมนและค่อนข้างช่วยให้ฉันใช้พื้นที่ฟังก์ชันของ Haskell เพื่อผูกตัวแปรได้ บางทีคุณเกือบจะอ่านสิ่งต่อไปนี้ได้!
pTy :: Tm a
pTy = fmap magic $
pil Set $ \ _A -> pil (pil _A $ \ _ -> Set) $ \ _B -> Set
kTy :: Tm a
kTy = fmap magic $
pil Set $ \ _G -> pil Set $ \ _A -> pil _A $ \ a -> pil _G $ \ g -> _A
sTy :: Tm a
sTy = fmap magic $
pil Set $ \ _G ->
pil (pil _G $ \ g -> Set) $ \ _A ->
pil (pil _G $ \ g -> pil (_A :$ g) $ \ _ -> Set) $ \ _B ->
pil (pil _G $ \ g -> pil (_A :$ g) $ \ a -> _B :$ g :$ a) $ \ f ->
pil (pil _G $ \ g -> _A :$ g) $ \ a ->
pil _G $ \ g -> _B :$ g :$ (a :$ g)
ด้วยการกำหนดเหล่านี้ฉันดึงข้อมูลย่อยที่เปิดอยู่ที่เกี่ยวข้องและเรียกใช้ผ่านการแปล
ชุดเครื่องมือเข้ารหัส de Bruijn
pil
นี่คือวิธีการที่จะสร้าง ประการแรกฉันกำหนดคลาสของFin
ชุดซ้ำซึ่งใช้สำหรับตัวแปร ทุกชุดดังกล่าวมีคอนสตรัครักษาemb
EDDING เป็นชุดข้างต้นบวกใหม่top
องค์ประกอบและคุณสามารถบอกพวกเขาออกจากกันคือฟังก์ชั่นบอกคุณถ้ามีค่าอยู่ในภาพของembd
emb
class Fin x where
top :: Su x
emb :: x -> Su x
embd :: Su x -> Maybe x
แน่นอนเราสามารถสร้างอินสแตนซ์Fin
สำหรับZe
และSuc
instance Fin Ze where
top = Ze
emb = magic
embd _ = Nothing
instance Fin x => Fin (Su x) where
top = Su top
emb Ze = Ze
emb (Su x) = Su (emb x)
embd Ze = Just Ze
embd (Su x) = fmap Su (embd x)
ตอนนี้ฉันสามารถกำหนดน้อยหรือเท่ากับได้ด้วยการดำเนินการที่อ่อนลง
class (Fin x, Fin y) => Le x y where
wk :: x -> y
wk
ฟังก์ชั่นควรฝังองค์ประกอบของx
เป็นที่ใหญ่ที่สุดในองค์ประกอบของy
เพื่อให้สิ่งที่พิเศษในการy
ที่มีขนาดเล็กและทำให้ในแง่เดดัชนี Bruijn ผูกพันมากขึ้นในประเทศ
instance Fin y => Le Ze y where
wk = magic
instance Le x y => Le (Su x) (Su y) where
wk x = case embd x of
Nothing -> top
Just y -> emb (wk y)
และเมื่อคุณจัดการสิ่งนั้นได้แล้ว skullduggery อันดับ n ก็จัดการส่วนที่เหลือ
lam :: forall x. Tm x -> ((forall y. Le (Su x) y => Tm y) -> Tm (Su x)) -> Tm x
lam s f = Lam s (f (Var (wk (Ze :: Su x))))
pil :: forall x. Tm x -> ((forall y . Le (Su x) y => Tm y) -> Tm (Su x)) -> Tm x
pil s f = Pi s (lam s f)
ฟังก์ชันลำดับที่สูงขึ้นไม่เพียง แต่ให้คำที่เป็นตัวแทนของตัวแปรเท่านั้น แต่ยังช่วยให้คุณมีสิ่งที่โอเวอร์โหลดซึ่งจะกลายเป็นตัวแทนที่ถูกต้องของตัวแปรในขอบเขตใด ๆ ที่สามารถมองเห็นตัวแปรได้ นั่นคือความจริงที่ว่าฉันประสบปัญหาในการแยกแยะขอบเขตที่แตกต่างกันตามประเภททำให้ตัวตรวจสอบตัวพิมพ์ของ Haskell มีข้อมูลเพียงพอที่จะคำนวณการขยับที่จำเป็นสำหรับการแปลเป็นตัวแทนของ de Bruijn ทำไมเลี้ยงสุนัขและเห่าตัวเอง?