ตรรกะเชิงผสมที่เทียบเท่ากับทฤษฎีประเภทสัญชาตญาณคืออะไร?


87

ฉันเพิ่งเรียนจบหลักสูตรของมหาวิทยาลัยซึ่งเป็นจุดเด่นของ Haskell และ Agda (ภาษาการเขียนโปรแกรมเชิงฟังก์ชันที่ขึ้นอยู่กับตัวพิมพ์) และสงสัยว่าจะสามารถแทนที่แคลคูลัสแลมบ์ดาด้วยตรรกะผสมได้หรือไม่ ด้วย Haskell สิ่งนี้ดูเหมือนจะเป็นไปได้โดยใช้ตัวรวม S และ K จึงทำให้ไม่มีจุด ฉันสงสัยว่า Agda เทียบเท่ากับอะไร กล่าวคือเราสามารถสร้างภาษาการเขียนโปรแกรมเชิงฟังก์ชันที่พิมพ์ขึ้นโดยพึ่งพา Agda โดยไม่ใช้ตัวแปรใด ๆ ได้หรือไม่?

นอกจากนี้ยังสามารถแทนที่การหาปริมาณด้วยตัวผสมได้หรือไม่? ฉันไม่รู้ว่านี่เป็นเรื่องบังเอิญ แต่ตัวอย่างเช่นการหาปริมาณสากลทำให้ลายเซ็นประเภทดูเหมือนนิพจน์แลมบ์ดา มีวิธีลบการหาปริมาณสากลออกจากลายเซ็นโดยไม่เปลี่ยนความหมายหรือไม่? เช่นใน:

forall a : Int -> a < 0 -> a + a < a

สามารถแสดงสิ่งเดียวกันโดยไม่ใช้ forall ได้หรือไม่?


21
เริ่มต้นด้วยการหาประเภทที่ขึ้นกับ K (ง่าย) และ S (ค่อนข้างมีขนดก) เป็นเรื่องน่าสนใจที่จะโยนค่าคงที่สำหรับ Set และ Pi จากนั้นลองสร้างชุดพื้นฐาน (ไม่สอดคล้องกัน) ใหม่: Set system ฉันคิดต่อไป แต่ฉันมีเครื่องบินให้จับ
pigworker

คำตอบ:


52

ดังนั้นฉันจึงคิดเกี่ยวกับมันอีกเล็กน้อยและก้าวหน้า นี่เป็นการแทงครั้งแรกในการเข้ารหัสระบบที่เรียบง่าย (แต่ไม่สอดคล้องกัน) ของ Martin-Löf Set : Setในรูปแบบผสมผสาน ไม่ใช่วิธีที่ดีที่จะทำให้เสร็จ แต่เป็นจุดเริ่มต้นที่ง่ายที่สุด ไวยากรณ์ของทฤษฎีประเภทนี้เป็นเพียงแลมด้า - แคลคูลัสที่มีคำอธิบายประกอบประเภท Pi-types และชุดจักรวาล

ทฤษฎีประเภทเป้าหมาย

เพื่อความสมบูรณ์ฉันจะนำเสนอกฎ บริบทความถูกต้องเพียงแค่บอกว่าคุณสามารถสร้างบริบทจากว่างเปล่าโดยการติดตัวแปรสดพำนักSets

                     G |- valid   G |- S : Set
--------------     ----------------------------- x fresh for G
  . |- 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
-------------- x:S in G     ----------------------------- S ={beta} T
  G |- x : S                  G |- s : T

ในรูปแบบเล็ก ๆ น้อย ๆ จากต้นฉบับฉันได้กำหนดให้แลมบ์ดาเป็นตัวดำเนินการผูกพันเพียงตัวเดียวดังนั้นอาร์กิวเมนต์ที่สองของ Pi ควรเป็นฟังก์ชันที่คำนวณวิธีที่ประเภทผลตอบแทนขึ้นอยู่กับอินพุต ตามแบบแผน (เช่นใน Agda แต่น่าเศร้าที่ไม่ได้อยู่ใน Haskell) ขอบเขตของ lambda จะขยายไปทางขวาให้มากที่สุดดังนั้นคุณมักจะปล่อยให้ abstractions ไม่ติดเครื่องหมายเมื่อเป็นอาร์กิวเมนต์สุดท้ายของตัวดำเนินการลำดับที่สูงกว่า: คุณจะเห็นว่าฉันทำ กับ Pi ประเภท AGDA ของคุณจะกลายเป็น(x : S) -> TPi 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        -- requires first arg in normal form
C S :. f :. a $. g  = f $. g $. (a :. g)  -- S f a g = f g (a g)   share environment
C K :. a $. g       = a                   -- K a g = a             drop environment
n $. g              = n :. norm g         -- guarantees output in normal form
infixl 4 $.

(แบบฝึกหัดสำหรับผู้อ่านคือการกำหนดประเภทของรูปแบบปกติและเพิ่มความคมชัดของประเภทของการดำเนินการเหล่านี้)

เป็นตัวแทนของทฤษฎีประเภท

ตอนนี้เราสามารถกำหนดไวยากรณ์สำหรับทฤษฎีประเภทของเราได้แล้ว

data Tm a
  = Var a
  | Lam (Tm a) (Tm (Su a))    -- Lam is the only place where binding happens
  | Tm a :$ Tm a
  | Pi (Tm a) (Tm a)          -- the second arg of Pi is a function computing a Set
  | 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 xx

การแปลข้อกำหนดเป็น 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               -- binds a variable, building a function
bra (V Ze)      = C S :. C K :. C K        -- the variable itself yields the identity
bra (V (Su x))  = C K :. V x               -- free variables become constants
bra (C c)       = C K :. C c               -- combinators become constant
bra (f :. a)    = C S :. bra f :. bra a    -- S is exactly lifted application

การพิมพ์ Combinators

การแปลแสดงให้เห็นถึงวิธีที่เราใช้ตัวผสมซึ่งทำให้เราได้เบาะแสว่าควรจะเป็นประเภทใด UและPเป็นเพียงตัวสร้างที่ตั้งค่าไว้ดังนั้นการเขียนประเภทที่ไม่ได้แปลและอนุญาต "สัญกรณ์ Agda" สำหรับ Pi เราควรมี

U : Set
P : (A : Set) -> (B : (a : A) -> Set) -> Set

KCombinator จะใช้ในการยกค่าของบางชนิดกับฟังก์ชั่นอย่างต่อเนื่องกว่าชนิดอื่นAG

  G : Set   A : Set
-------------------------------
  K : (a : A) -> (g : G) -> A

SCombinator ถูกนำมาใช้เพื่อการใช้งานลิฟท์มากกว่าประเภทตามที่ทุกชิ้นส่วนอาจขึ้นอยู่

  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
----------------- A ={norm} B
  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ชุดซ้ำซึ่งใช้สำหรับตัวแปร ทุกชุดดังกล่าวมีคอนสตรัครักษาembEDDING เป็นชุดข้างต้นบวกใหม่topองค์ประกอบและคุณสามารถบอกพวกเขาออกจากกันคือฟังก์ชั่นบอกคุณถ้ามีค่าอยู่ในภาพของembdemb

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              -- Ze is the only, so the highest
  emb = magic
  embd _ = Nothing      -- there was nothing to embed

instance Fin x => Fin (Su x) where
  top = Su top          -- the highest is one higher
  emb Ze     = Ze            -- emb preserves Ze
  emb (Su x) = Su (emb x)    -- and Su
  embd Ze      = Just Ze           -- Ze is definitely embedded
  embd (Su x)  = fmap Su (embd x)  -- otherwise, wait and see

ตอนนี้ฉันสามารถกำหนดน้อยหรือเท่ากับได้ด้วยการดำเนินการที่อ่อนลง

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    -- nothing to embed

instance Le x y => Le (Su x) (Su y) where
  wk x = case embd x of
    Nothing  -> top          -- top maps to top
    Just y   -> emb (wk y)   -- embedded gets weakened and embedded

และเมื่อคุณจัดการสิ่งนั้นได้แล้ว 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 ทำไมเลี้ยงสุนัขและเห่าตัวเอง?


นี่อาจจะดูโง่มาก แต่ภาพนี้จะเปลี่ยนไปอย่างไรถ้าคุณเพิ่มตัวFรวมเข้าด้วยกัน? Fทำหน้าที่แตกต่างกันไปขึ้นอยู่กับการโต้แย้งครั้งแรก: ถ้าAเป็นอะตอมMและNมีข้อกำหนดและPQเป็นคอมโพสิตแล้วและFAMN -> M F(PQ)MN -> NPQนี้ไม่สามารถแสดงในSK(I)แคลคูลัส แต่สามารถแสดงเป็นK FFเป็นไปได้ไหมที่จะขยาย MLTT แบบไม่เสียคะแนนด้วยสิ่งนี้
kram1032

ฉันค่อนข้างแน่ใจว่ามีปัญหากับขั้นตอนนามธรรมของวงเล็บนี้โดยเฉพาะส่วน "ตัวผสมกลายเป็นค่าคงที่" ซึ่งแปลλx.cเป็น Kc สำหรับตัวผสม c ∈ {S, K, U, P} ปัญหาคือตัวผสมเหล่านี้เป็นโพลีมอร์ฟิกและอาจใช้ในประเภทที่ขึ้นอยู่กับ x คำแปลนี้ไม่สามารถรักษาประเภทดังกล่าวไว้ได้ ตามตัวอย่างที่เป็นรูปธรรมคำว่าλ (A : Set) → λ (a : A) → atype (A : Set) → (a : A) → Aถูกแปลเป็นS(S(KS)(KK))(KK)ซึ่งไม่สามารถใช้กับประเภทที่ประเภทของอาร์กิวเมนต์ที่สองขึ้นอยู่กับอาร์กิวเมนต์แรก
Anders Kaseorg

8

ฉันเดาว่า "Bracket Abstraction" ยังใช้ได้กับประเภทที่อ้างอิงในบางสถานการณ์ ในส่วนที่ 5 ของกระดาษต่อไปนี้คุณจะพบประเภท K และ S บางประเภท:

ความบังเอิญที่ชั่วร้าย แต่มีความหมาย
ไวยากรณ์ที่ปลอดภัยขึ้นอยู่กับประเภทและการประเมิน
Conor McBride, University of Strathclyde, 2010

การแปลงนิพจน์แลมบ์ดาเป็นนิพจน์คอมบิเนเตอร์โดยประมาณนั้นสอดคล้องกับการแปลงหลักฐานการหักตามธรรมชาติให้เป็นหลักฐานสไตล์ฮิลแบร์ต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.