直観主義型理論に相当するコンビネータ論理とは何ですか?


87

私は最近、HaskellとAgda(依存型関数型プログラミング言語)を取り上げた大学のコースを修了しましたが、これらのラムダ計算をコンビネータ論理に置き換えることができるかどうか疑問に思いました。Haskellでは、これはSおよびKコンビネータを使用して可能であるように思われるため、ポイントフリーになります。アグダに相当するものは何だろうと思っていました。つまり、変数を使用せずに、依存型の関数型プログラミング言語をAgdaと同等にすることはできますか?

また、どういうわけか定量化をコンビネータに置き換えることは可能ですか?これが偶然かどうかはわかりませんが、たとえば全称記号を使用すると、型シグネチャがラムダ式のように見えます。意味を変えずに型シグネチャから全称記号を削除する方法はありますか?例:

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

フォラルを使わなくても同じことが表現できますか?


21
K(簡単)とS(やや毛深い)で可能な最も依存型を理解することから始めます。SetとPiの定数を投入してから、基本的な(一貫性のない)Set:Setシステムを再構築してみるのは興味深いことです。さらに考えますが、捕まえる飛行機があります。
pigworker 2012

回答:


52

それで、もう少し考えて、少し進歩しました。これは、Martin-Löfの楽しくシンプルな(しかし一貫性のない)Set : Setシステムを組み合わせスタイルでエンコードする最初の試みです。終了するのは良い方法ではありませんが、開始するのに最も簡単な場所です。この型理論の構文は、型注釈、Pi型、およびユニバースセットを含むラムダ計算です。

ターゲット型理論

完全を期すために、ルールを示します。コンテキストの妥当性は、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の2番目の引数は、戻り値の型が入力に依存する方法を計算する関数である必要があります。慣例により(たとえばAgdaでは、残念ながらHaskellではそうではありません)、ラムダのスコープは可能な限り右方向に拡張されるため、抽象化が高次演算子の最後の引数である場合は、抽象化を括弧なしのままにすることができます。それはPiです。Agdaタイプはに(x : S) -> TなりPi S \ x:S -> Tます。

余談。抽象化の型を合成できるようにする場合は、ラムダの型注釈が必要です。手口として型チェックに切り替える場合でも(\ x -> t) s、のようなベータレデックスをチェックするための注釈が必要です。方法がないためです。全体のタイプからパーツのタイプを推測します。現代の設計者には、タイプを確認し、構文そのものからベータ版を除外することをお勧めします。)

余談。このシステムはSet:Set、さまざまな「嘘つきのパラドックス」のエンコードを可能にするため、一貫性がありません。Martin-Löfがこの理論を提案したとき、Girardは彼自身の一貫性のないシステムUでエンコードを送信しました。Hurkensによるその後のパラドックスは私たちが知っている最も近い有毒な構造。)

コンビネータ構文と正規化

とにかく、PiとSetの2つの追加の記号があるので、おそらくS、Kと2つの追加の記号を組み合わせた翻訳を管理するかもしれません。私は宇宙に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この構文には、型で表される自由変数を含める手段が含まれていることに注意してください。私の側の反射であることに加えて(名前に値するすべての構文は、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)

私は、ベルガルドとフックの方法でド・ブラウン・インデックス表現を使用します(バードとパターソンによって普及したように)。この型にSu aa、よりも1つ多くの要素があり、バインダーの下の自由変数の型として使用します。Ze新しくバインドされた変数としてSu x、古い自由変数のシフト表現として使用しますx

用語をコンビネータに翻訳する

これで、ブラケットの抽象化に基づいて、通常の翻訳を取得します。

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

コンビネータの入力

この翻訳は、コンビネータの使用方法を示しています。これにより、コンビネータのタイプがどうあるべきかについてかなりの手がかりが得られます。UそしてPちょうどパイのための「Agda表記を」非翻訳型を書き込むと可能なので、コンストラクタに設定されている、我々は持っている必要があります

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

Kコンビネータは、いくつかのタイプの値を持ち上げるために使用されるAいくつかの他のタイプにわたって一定の関数にG

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

Sコンビネータは、部品のすべてが依存し得るその上に型、オーバーアプリケーションを持ち上げるために使用されます。

  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

しかし、問題があります。コンビネータの型は、コンビネータ型理論ではなく、通常の型理論で書いています。幸いなことに、私は翻訳を行うマシンを持っています。

コンビネータ型システム

---------
  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!の組み合わせのプレゼンテーション

まだ少し問題があります。システムの構文はあなたを推測する方法を与えていないGABのパラメータSと同様のためKだけの観点から、。これに対応して、タイピングの派生をアルゴリズムで検証することはできますが、元のシステムのようにコンビネータ項をタイプチェックすることはできません。うまくいくかもしれないのは、SとKの使用に関するタイプ注釈を付けるためにタイプチェッカーへの入力を要求し、派生を効果的に記録することです。しかし、それはワームの別の缶です...

あなたが始めるのに十分熱心であるならば、これは立ち止まるのに良い場所です。残りは「舞台裏」のものです。

コンビネータのタイプの生成

関連する型理論用語からの括弧抽象化変換を使用して、これらの組み合わせ型を生成しました。私がそれをどのように行ったかを示し、この投稿を完全に無意味ではないようにするために、私の機器を提供させてください。

次のように、パラメーターを完全に抽象化したコンビネーターのタイプを記述できます。pilPiとラムダを組み合わせてドメインタイプの繰り返しを回避する便利な関数を利用し、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 Encoding Toolkit

ビルド方法は次のとおりpilです。まず、Fin変数に使用されるiteセットのクラスを定義します。そのようなすべてのセットには、emb上記のセットへのコンストラクター保存eddedtopと新しい要素があり、それらを区別することができます。embd関数は、値がのイメージにあるかどうかを通知しますemb

class Fin x where
  top :: Su x
  emb :: x -> Su x
  embd :: Su x -> Maybe x

もちろん、インスタンス化FinZeSuc

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より多くのローカルでバインドド・ブラン・インデックスの観点から、より小さな、ひいてはです。

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

そして、それを整理したら、ランク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タイプチェッカーにdeBruijn表現への変換に必要なシフトを計算するのに十分な情報を提供します。なぜ犬を飼って自分で吠えるのですか?


これは非常にばかげているかもしれませんが、Fコンビネータを追加すると、この画像はどのように変化しますか?F最初の引数に応じて動作が異なります。AがアトムでMあり、Nが用語でPQあり、が複合である場合FAMN -> M、およびF(PQ)MN -> NPQ。これはSK(I)微積分では表現できませんが、Kとして表現できますFF。これでポイントフリーMLTTを拡張することは可能ですか?
kram1032 2016年

このブラケット抽象化手順には問題があると確信しています。具体的には、コンビネータc∈{S、K、U、P}のλx.cをKcに変換する「コンビネータが一定になる」部分です。問題は、これらのコンビネータが多型であり、xに依存する型で使用される可能性があることです。このようなタイプは、この翻訳では保持できません。具体的な例として、λ (A : Set) → λ (a : A) → a型の用語(A : Set) → (a : A) → Aはに変換されますS(S(KS)(KK))(KK)。これは、2番目の引数の型が最初の引数に依存する型では使用できません。
Anders Kaseorg 2018

8

「ブラケットの抽象化」は、状況によっては依存型でも機能すると思います。次の論文のセクション5には、いくつかのKタイプとSタイプがあります。

とんでもないが意味のある偶然
依存型の型安全な構文と評価
ConorMcBride、ストラスクライド大学、2010年

ラムダ式を組み合わせ式に変換することは、自然演繹証明をヒルベルトスタイルの証明に変換することにほぼ対応します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.