代数的データ型の代数の乱用-なぜこれが機能するのですか?


289

代数的データ型の「代数的」表現は、数学のバックグラウンドを持つ誰かに非常に暗示的に見えます。私の言いたいことを説明してみましょう。

基本的なタイプを定義した

  • 製品
  • 連合 +
  • シングルトン X
  • 単位 1

そして、for X•X2Xfor X+Xceteraの短縮形を使用して、リンクされたリストなどの代数式を定義できます。

data List a = Nil | Cons a (List a)L = 1 + X • L

そして二分木:

data Tree a = Nil | Branch a (Tree a) (Tree a)T = 1 + X • T²

さて、数学者としての私の最初の本能は、これらの表現とナッツ行く、とのために解決しようとすることであるLT。繰り返し置換することでこれを行うことができますが、表記を恐ろしく悪用し、自由に並べ替えられるふりをする方がはるかに簡単です。たとえば、リンクリストの場合:

L = 1 + X • L

(1 - X) • L = 1

L = 1 / (1 - X) = 1 + X + X² + X³ + ...

ここで、のべき級数展開を1 / (1 - X)まったく正当化されていない方法で使用して、興味深い結果を導き出しました。つまり、L型はであるかNil、1つの要素を含むか、2つの要素を含むか、または3などです。

二分木に対して行うと、より興味深いものになります。

T = 1 + X • T²

X • T² - T + 1 = 0

T = (1 - √(1 - 4 • X)) / (2 • X)

T = 1 + X + 2 • X² + 5 • X³ + 14 • X⁴ + ...

再び、級数展開を使用します(Wolfram Alphaで実行)。これは、1つの要素を持つ1つのバイナリツリー、2つの要素を持つ2つのバイナリツリー(2番目の要素は左または右のブランチにあることができます)、3つの要素を持つ5つのバイナリツリーなどの非自明な(私にとって)事実を表します。

だから私の質問は-私はここで何をしているのですか?これらの操作は正当化されていないように見えますが(とにかく代数的データ型の平方根は正確に何ですか?)、これらは適切な結果をもたらします。2つの代数的データ型の商は、コンピュータサイエンスで何らかの意味がありますか、それとも単なる表記上のトリックですか?

そして、おそらくもっと興味深いことに、これらのアイデアを拡張することは可能ですか?たとえば、型に対する任意の関数を許可する型の代数の理論はありますか、または型はべき級数表現を必要としますか?関数のクラスを定義できる場合、関数の合成には意味がありますか?


19
:あなたはこの興味深い/関連見つけるかもしれないblog.lab49.com/archives/3011
シャン

4
すべてのノードにデータを保存する場合はそうではありません。のようBranch x (Branch y Nil Nil) Nilに見えるか、またはのように見えBranch x Nil (Branch y Nil Nil)ます。
Chris Taylor

4
@nlucaroni:ボトムはタイプではなく値です。真のゼロ型はその型の値をまったく持たないため、底を無視しない限りHaskellでは不可能です。ボトム値を考慮に入れると、ボトムのみを含むタイプはユニットタイプになり、ほとんどの場合役に立ちません。また、他の多くのものが壊れます。
CAマッキャン

3
私はそれがHaskellの一般的な慣習であることに同意します、それはまだばかげています。つまり、「ボトム」の使い方がロジックとタイプ理論の使い方とは異なるということです。純粋なコードから同じように見ても同じにはなりません。「厄介な分隊への取り組み」は、Haskellのセマンティクスに「悪い値」のホストが多数あり、そのループが永久にループし、例外をスローすることが明らかに同じではないことを明らかにします。一方を他方に置き換えることは、有効な方程式論ではありません。Haskellはこれらの不正な値を記述するための語彙を持ってundefinedthrow我々はそれを使用する必要がありますなど、。
フィリップJF、

17
私の心はこの質問に
圧倒

回答:


138

免責事項:⊥を考慮に入れると、これの多くは実際には正しく機能しません。単純化するために、これを露骨に無視します。

いくつかの最初のポイント:

  • 特にだ-注ことは、「労働組合は、」おそらく、ここでA + Bのための最善の用語ではない互いに素の組合双方が自分のタイプが同じであっても区別されているので、2種類の。価値のあるものについては、より一般的な用語は単に「合計タイプ」です。

  • シングルトンタイプは、事実上すべてのユニットタイプです。それらは代数操作の下でも同じように動作し、さらに重要なことに、存在する情報の量はまだ保持されます。

  • おそらくゼロ型も必要です。Haskellはそれをとして提供していVoidます。タイプが1の値が1つあるのと同様に、タイプがゼロの値はありません。

ここにはまだ1つの主要な操作がありませんが、すぐに戻ってきます。

おそらくお気づきのとおり、Haskellはカテゴリ理論から概念を借用する傾向があり、上記のすべては次のように非常に簡単な解釈を持っています。

  • 内のオブジェクトA及びB所与Hask、彼らの製品A×Bは二つの突起可能(最大同型に)固有の型であるFST A×B→Aと:SND:任意のタイプCと機能所与A×B→B、F:C→A、g:C→Bペアリングf &&& g:C→A×B を定義して、fst∘ (f &&& g) = fとなるようにして、gについても同様にすることができます。パラメトリック性は、普遍的なプロパティを自動的に保証し、私の名前の微妙ではない選択はあなたにアイデアを与えるはずです。(&&&)オペレータがで定義されているControl.Arrow方法で、。

  • 上記の双対は、副産物A + Bであり、注入はinl:A→A + Bおよびinr:B→A + Bです。ここで、任意のタイプCおよび関数f:A→C、g:B→Cを指定すると、次のことができます。対合fを定義する||| g:A + B→Cなので、明らかな同等性が成り立ちます。ここでも、パラメトリック性により、トリッキーなパーツのほとんどが自動的に保証されます。この場合、標準的な注入は単純LeftRightあり、ペアリングは関数eitherです。

積および合計タイプのプロパティの多くは、上記から導き出すことができます。任意シングルトンタイプの端子オブジェクトであることに注意Hask、任意の空の型が最初のオブジェクトです。

前述の行方不明の操作に戻ると、中デカルト閉圏あなたが持っている指数オブジェクト、そのカテゴリの矢印に対応します。矢印は関数であり、オブジェクトはkind *を持つ型であり、型はA -> B実際に、型の代数的操作のコンテキストでB Aとして動作します。これが成り立つ理由が明らかでない場合は、タイプを検討してくださいBool -> A。たった2つの可能な入力で、そのタイプの機能は、型の2つの値と同型であるA、すなわち(A, A)。なぜならMaybe Bool -> A、3つの可能な入力があるからです。また、代数表記を使用するように上記のペアリングの定義を言い換えると、アイデンティティC A ×C B = Cが得られることに注意してください。A + B

なぜ、特に級数展開の使用が正当化される理由- -上記の多くは種類の「住民」(すなわち、その型を有する別個の値)の順序でのことをいう。このすべてが理にかなっています代数的振る舞いを示すため。その見方を明確にするために:

  • 製品タイプ(A, B)は、Aおよびからの値を表し、それぞれB個別に取得されます。したがって、固定値の場合a :: A、の(A, B)各居住者に対してtypeの値が1つありますB。これはもちろんデカルト積であり、製品タイプの居住者数は要因の居住者数の積です。

  • 合計タイプEither A Bは、Aまたはからの値を表しB、左と右のブランチが区別されます。前述のように、これはばらばらの労働組合であり、合計タイプの住民の数は、被加数の住民の数の合計です。

  • 指数型B -> Aは、typeの値からtypeの値へのマッピングを表しBますA。任意の固定引数に対してb :: B、任意の値をA割り当てることができます。typeの値は、B -> Aのような多くのコピーの積に相当する各入力に対して1つのこのようなマッピング、ピックAとしてBしたがって住民、べき乗を有しています。

型をセットとして扱うことは最初は魅力的ですが、このコンテキストでは実際にはあまりうまく機能しません。セットの標準的なユニオンではなく、ディスユニオンなユニオンがあり、交差や他の多くのセット演算の明確な解釈はありません。通常、セットメンバーシップは気にしません(タイプチェッカーに任せます)。

一方、上記の構文は、住民のカウントについて多くの時間を費やしており、の可能な値を列挙することは、ここでは有用な概念です。これはすぐに列挙型の組み合わせ論につながります。リンクされたWikipediaの記事を参照すると、最初に行うことの1つは、「ペア」と「ユニオン」を製品と合計のタイプとまったく同じ意味で定義することです。関数を生成すると、Haskellのリストとまったく同じ「シーケンス」に対して同じことを行います。


編集:ああ、そしてここに私が思うにポイントを驚くほど実証すると思うクイックボーナスがあります。コメントで、ツリータイプのT = 1 + T^2場合はアイデンティティを導出できるT^6 = 1と述べましたが、これは明らかに間違っています。しかし、T^7 = T ないホールドをし、木と木の7タプル間の全単射は、直接参照を構築することができます アンドレアスブラスの「7つのツリーインワン」

編集×2:他の回答で言及されている「タイプの派生」構築について、分割の概念やその他の興味深いものなど、アイデアをさらに発展させた同じ著者のこの論文もお楽しみいただけます。



26
@acfoltzer:ありがとう!:]そして、はい、それはこれらのアイデアを発展させる素晴らしい論文です。ご存知のように、SOに対する私の評判の少なくとも5%は「コナーマクブライドの論文の1つを人々が理解するのを助ける」
CA McCann

45

二分木はT=1+XT^2、型の半環の方程式によって定義されます。構成によりT=(1-sqrt(1-4X))/(2X)、複素数の半環の同じ方程式で定義されます。したがって、同じクラスの代数構造で同じ方程式を解いているとすれば、実際にはいくつかの類似点があることは驚くに値しません。

問題は、複素数の半環の多項式について推論する場合、通常、複素数が環または場さえも形成するという事実を使用するため、半環には適用されない減算などの演算を使用していることがわかります。しかし、方程式の両側からキャンセルできるルールがある場合は、引数からの減算を排除できることがよくあります。これは、フィオーレとレンスターによって証明された種類のことであり、リングに関する多くの議論がセミリングに転送できることを示しています。

これは、リングに関する多くの数学的な知識を確実に型に転送できることを意味します。結果として、複素数またはべき級数(正式なべき級数の環)を含むいくつかの引数は、完全に厳密な方法で型に引き継がれます。

しかし、この話にはこれ以上のものがあります。2つのべき級数が等しいことを示すことで、2つのタイプが等しい(たとえば)ことを証明することは1つです。しかし、べき級数の項を調べて、型に関する情報を推測することもできます。ここでの正式な声明がどうあるべきかわかりません。(私は、密接に関連しているが、種はタイプと同じではないいくつかの研究には、組み合わせ種に関するブレント・ヨージーの論文をお勧めします。)

私が完全に心が吹いているのは、あなたが発見したものは微積分に拡張できるということです。微積分に関する定理は、タイプの半環に移すことができます。実際、有限差分に関する議論でさえも転送することができ、数値解析からの古典的な定理は型理論の解釈を持っていることがわかります。

楽しんで!


この差別化/ 1ホールのコンテキストはかなりクールです。これがまっすぐかどうか見てみましょう。代数表現のペアにP = X^2は導関数がありdP = X + XEitherペアの1ホールのコンテキストにもあります。それはいいね。「統合」Eitherしてペアを取得することもできます。しかし、Maybe(typeを使ってM = 1 + X)「統合」しようとする\int M = X + X^2 / 2と、無意味なものが必要になります(タイプの半分は何ですか?)これは、それMaybeが他のタイプの1穴コンテキストではないことを意味しますか?
クリステイラー

6
@ChrisTaylor:1ホールのコンテキストは、製品内部の位置に関する情報を保持します。つまり、(A,A)その中に穴があるAと、穴がどちら側にあるかが少しわかります。一A人で埋めるべき明確な穴がないため、それを「統合」することはできません。この場合の欠落情報のタイプはもちろんです2
CAマッキャン


@ user207442、1本の木と7本の木の間の全単射についても何かしませんでしたか?私は私の回答でそのことについての論文にリンクしましたが、私はあなたのブログで最初にそれについて読んだことを覚えていると誓うことができました。
カリフォルニア州マッキャン、2012

1
@ChrisTaylor有限の(実際には「分割された」)違いには、これがあります:strictlypositive.org/CJ.pdfしかし、その時点で、Conorは違いを説明していることに気付きませんでした。これを書くのは難しいかもしれませんが、私はこれを書きました:blog.sigfpe.com/2010/08/…私は論文を書きますが、私はそれらを完成するのがあまり得意ではありません。
sigfpe

22

あなたがしていることは、再帰関係を拡大しているだけのようです。

L = 1 + X  L
L = 1 + X  (1 + X  (1 + X  (1 + X  ...)))
  = 1 + X + X^2 + X^3 + X^4 ...

T = 1 + X  T^2
L = 1 + X  (1 + X  (1 + X  (1 + X  ...^2)^2)^2)^2
  = 1 + X + 2  X^2 + 5  X^3 + 14  X^4 + ...

また、型の演算のルールは算術演算のルールのように機能するため、代数的手段を使用して、反復関係を拡張する方法を理解するのに役立ちます(これは明らかではないため)。


1
「型の演算のルールは算術演算のルールのように機能するので...」-しかし、そうではありません。除算や平方根は言うまでもなく、型の減算という概念はありません。だから私の質問はX、実数の要素であると仮定する代数的操作から型に関する真のステートメントにいつ移行できるか、さらに、が対応(n次数項の係数)<=>(数値n要素を保持するタイプの種類)の由来は?
クリステイラー

1
例えば、ツリーのための式から(T = 1 + T^2)私は得ることができますT^6 = 1(つまり、ソリューションがためにx^2 - x + 1 = 0団結の第六の根である)が、それは明らかだありません 6分木からなる製品の種類は、ユニットと同等であることは事実()
クリステイラー

3
@ChrisTaylor、しかしとの間に同型があるため、そこで何かが起こっています。cf. arxiv.org/abs/math/9405205T^7T
ルキ

7
@ChrisTaylor、ここで考えるべきことがあります。新しい代数演算を追加するときは、既存の演算の特性を壊さないようにしてください。2つの異なる方法で同じ答えを得ることができる場合、彼らは同意する必要があります。したがって、そこで提供するすべての任意の表現のためにはL = 1 + X * L、より良い一貫性によって、あなたシリーズが展開するときに取得することを同じ一つでした。それ以外の場合は、結果を逆方向に実行して、実数について誤った結果を得る可能性があります。
luqui

2
@ChrisTaylor確かに型の分割の概念があります。詳細については、「商型」を検索してください。多項式除算とうまく対応するかどうかはわかりません。それはたまたまかなり非現実的ですが、それはそこにあります。
Doug McClean

18

完全な答えはありませんが、これらの操作は「うまくいく」傾向があります。関連する論文があるかもしれないフィオーレとレンスターによって複素数などのカテゴリの[オブジェクト -読みながら、私はその1に出くわした関連被写体にSIGFPEのブログを。そのブログの残りの部分は、同様のアイデアの宝庫であり、チェックする価値があります。

ところで、データ型を区別することもできます。これにより、データ型に適したZipperが得られます。


12
ジッパーのトリックは素晴らしいです。理解できたらいいのに。
散布

また、Schemeで区切られた継続を使用してジッパーを作成することもできます。これにより、ジッパーを汎用的に派生させることができます。
Jon Purdy、2012

10

通信プロセスの代数(ACP)は、プロセスの同様の種類の式を扱います。選択とシーケンスの演算子として、関連する中立要素を使用して、加算と乗算を提供します。これらに基づいて、並列処理や中断などの他の構造の演算子があります。http://en.wikipedia.org/wiki/Algebra_of_Communicating_Processesを参照してください。「プロセス代数の簡単な歴史」という名前の論文もオンラインで公開されています。

私はACPでプログラミング言語の拡張に取り組んでいます。昨年4月、Scala Days 2012で研究論文を発表しました。http://code.google.com/p/subscript/から入手できます。

カンファレンスで、バッグの並列再帰仕様を実行するデバッガーのデモを行いました。

バッグ= A; (バッグ&a)

ここで、Aと入力および出力アクションを表します。セミコロンとアンパサンドは、シーケンスと並列処理を表します。前のリンクから到達可能なSkillsMatterのビデオを参照してください。

より同等のバッグ仕様

L = 1 + X•L

だろう

B = 1 + X&B

ACPは、公理を使用して選択と順序の観点から並列処理を定義します。ウィキペディアの記事を参照してください。バッグの類推は何のためにあるのだろう

L = 1 /(1-X)

ACPスタイルのプログラミングは、テキストパーサーやGUIコントローラに便利です。などの仕様

searchCommand = clicked(searchButton)+ key(Enter)

cancelCommand = clicked(cancelButton)+ key(Escape)

「クリック」と「キー」の2つの改良点を暗黙的にすることで、より簡潔に書き留めることができます(Scalaが関数で許可するようなもの)。したがって、次のように書くことができます。

searchCommand = searchButton + Enter

cancelCommand = cancelButton + Escape

右側には、プロセスではなくデータであるオペランドが含まれています。このレベルでは、これらのオペランドをプロセスに変換する暗黙の調整を知る必要はありません。それらは必ずしも入力アクションに洗練されるとは限りません。たとえば、テストロボットの仕様では、出力アクションも適用されます。

プロセスはこの方法でデータをコンパニオンとして取得します。したがって、「アイテム代数」という用語を作ります。


6

微積分およびマクラウリンシリーズとタイプ

ここにもう1つのマイナーな追加があります-級数展開の係数が「機能する」理由に関する組み合わせの洞察、特に微積分からのテイラー-マクローリンアプローチを使用して導出できる系列に焦点を当てています。注意:操作リストタイプのシリーズ展開の例は、Maclaurinシリーズです。

他の回答とコメントは代数型式(合計、積、指数)の振る舞いを扱うため、この回答はその詳細を省き、「計算」型に焦点を当てます。

この回答では、カンマが逆になっていることがわかります。2つの理由があります。

  • 私たちは、あるドメインから別のドメインのエンティティに解釈を与えるビジネスを行っており、このような外国の概念をこのように区切ることが適切であると思われます。
  • 一部の概念はより厳密に形式化することができますが、形よりもアイデアの方が詳細よりも重要である(そして書くスペースが少ない)ように見えます。

マクラウリンシリーズの定義

関数のMaclaurinシリーズf : ℝ → ℝは次のように定義されます

f(0) + f'(0)X + (1/2)f''(0)X² + ... + (1/n!)f⁽ⁿ⁾(0)Xⁿ + ...

where f⁽ⁿ⁾はのnth導関数を意味しfます。

タイプで解釈されるMaclaurinシリーズを理解できるようにするには、タイプコンテキストで3つのことを解釈する方法を理解する必要があります。

  • (おそらく複数の)導関数
  • 関数を適用する 0
  • のような用語 (1/n!)

そして、分析からのこれらの概念は、型の世界で適切な対応物を持っていることがわかります。

「適切な相手」とはどういう意味ですか?それは同型の風味を持っている必要があります-両方向で真実を維持できれば、1つのコンテキストで導き出せるファクトを他のコンテキストに転送できます。

型付き微積分

では、型式の導関数はどういう意味ですか?型式とファンクタの大規模で適切に動作する(「微分可能」)クラスの場合、適切に解釈されるように十分に同様に動作する自然な操作があることがわかります。

パンチラインを台無しにするために、差別化に類似した操作は、「ワンホー​​ルコンテキスト」を作成する操作です。これは、この特定のポイントをさらに拡張するのに最適な場所ですが、1ホールコンテキスト(da/dx)の基本概念は、x(タイプa)の用語から特定のタイプ()の単一のサブアイテムを抽出した結果を表すことです。サブアイテムの元の場所を決定するために必要な情報を含む、その他すべての情報。たとえば、リストの1ホールコンテキストを表す1つの方法は、2つのリストを使用することです。1つは抽出されたリストの前に来たアイテム用で、もう1つは後に来たアイテム用です。

この操作を差別化して特定する動機は、以下の観察にあります。da/dxtypeのa穴を持つ型の1穴コンテキストの型を意味するように記述しxます。

d1/dx = 0
dx/dx = 1
d(a + b)/dx = da/dx + db/dx
d(a × b)/dx = a × db/dx + b × da/dx
d(g(f(x))/dx = d(g(y))/dy[f(x)/a] × df(x)/dx

ここで、1および0はそれぞれ、正確に一つと正確にゼロ住民との種類を表し、+そして×いつものように和と積の種類を表します。fおよびgは、型関数または型式の前者を表すために使用され、前の式のすべて[f(x)/a]を置換する操作を意味します。f(x)a

これはポイントフリースタイルで記述f'でき、function型の微分関数を意味するように記述fできます。

(x ↦ 1)' = x ↦ 0
(x ↦ x)' = x ↦ 1
(f + g)' = f' + g'
(f × g)' = f × g' + g × f'
(g ∘ f)' = (g' ∘ f) × f'

それは好ましいかもしれません。

型とファンクタの同型クラスを使用して導関数を定義すると、等式を厳密かつ正確にすることができます。

ここで、特に、加算、乗算、および合成の代数演算に関連する微積分のルール(Sum、Product、およびChainルールと呼ばれることが多い)が、「穴をあける」操作に正確に反映されていることに気付きます。さらに、定数式または用語x自体に「穴を開ける」基本ケースも微分として振る舞うので、帰納法により、すべての代数型式に対して微分のような動作が得られます。

微分を解釈できるようになりました。n型式の「導関数」とはdⁿe/dxⁿどういう意味ですか?これは、n場所のコンテキストを表すnタイプです。タイプの条件で「満たされる」と、がx生成されますe。' (1/n!)'に関連する別の重要な観察があります。

型ファンクターの不変部分:関数を0に適用する

0型の世界ではすでに、メンバーのない空の型の解釈があります。組み合わせの観点から、型関数をそれに適用するとはどういう意味ですか?より具体的に言えば、f型関数であるとすると、どのf(0)ように見えますか?まあ、私たちは確かにタイプの何かにアクセスすることはできません0ので、それf(x)を必要とする構築xは利用できません。残っているのは、それらの不在下でアクセス可能な用語であり、タイプの「不変」または「定数」部分と呼ぶことができます。

明確な例として、Maybe代数的にとして表すことができる関手を取り上げx ↦ 1 + xます。これをに適用すると0、次のようになります。これは、次の1 + 0ようなものです。1可能な値は値だけNoneです。リストの場合も同様に、空のリストに対応する用語のみを取得します。

これを元に戻し、型f(0)を数値として解釈する場合、それは、(任意のの)型の用語のにアクセスできないと取得できる数、つまり「空のような」用語の数と考えることができます。。f(x)xx

まとめ:Maclaurinシリーズの完全な解釈

(1/n!)型としての適切な直接解釈を考えることができないと思います。

私たちが考える場合は、しかし、種類f⁽ⁿ⁾(0)以上の光の中では、我々はそれがの種類として解釈できることがわかりnタイプの任期でインプレースコンテキストすでに含まれていません我々は彼らに「統合」するとき、ある- 回、結果の項には正確に sが含まれます。次に、型としての数の解釈(Maclaurinシリーズの係数のように)は、そのような空の場所のコンテキストがいくつあるかを数えるだけです。もうすぐです!f(x) xn n xf⁽ⁿ⁾(0)fn

しかし、どこに(1/n!)行くのでしょうか?タイプ「微分」のプロセスを調べると、複数回適用すると、サブタームが抽出される「順序」が保持されることがわかります。たとえば(x₀, x₁)、タイプの用語x × xと「穴をあける」操作を2回考えてみます。両方のシーケンスを取得します

(x₀, x₁)  ↝  (_₀, x₁)  ↝  (_₀, _₁)
(x₀, x₁)  ↝  (x₀, _₀)  ↝  (_₁, _₀)
(where _ represents a 'hole')

2! = 22つから2つの要素を取り、順序を維持する方法があるため、両方とも同じ用語に由来します。一般に、から要素を取得するn!方法があります。だから、持ってファンクタ型の構成の数のカウントを取得するために要素を、我々はタイプカウントする必要がありによって、分裂を、正確にマクローリン級数の係数のように。nnnf⁽ⁿ⁾(0)n!

したがって、除算n!はそれ自体として単純に解釈可能であることがわかります。

最終的な考え:「再帰的な」定義と分析

最初に、いくつかの観察:

  • 関数f:ℝ→ℝに導関数がある場合、この導関数は一意です
  • 同様に、関数f:ℝ→ℝが分析的である場合、対応する多項式シリーズは1つだけです。

連鎖規則があるので、型微分を同型クラスとして形式化する暗黙微分を使用できます。しかし、暗黙の微分は、減算や除算のようなエイリアンの操作を必要としません!したがって、これを使用して再帰的な型定義を分析できます。リストの例を挙げると、

L(X) ≅ 1 + X × L(X)
L'(X) = X × L'(X) + L(X)

そして評価することができます

L'(0) = L(0) = 1

Maclaurinシリーズの係数を取得します。

しかし、これらの式は暗黙的にのみ厳密に「微分可能」であると確信しているため、導関数が確実に一意である関数ℝ→ℝとの対応があるため、「違法な操作、結果は有効です。

同様に、2番目の観測を使用するには、関数ℝ→(との対応(準同型か?)のため、関数 Maclaurin級数を持つことを満たしていれば、すべて、上で概説した原則を適用して、厳密にすることができます。

関数の構成に関する質問については、チェーンルールが部分的な答えを提供していると思います。

これが適用されるHaskellスタイルのADTの数はわかりませんが、すべてではないにしても多くあると思います。私はこの事実の本当に素晴らしい証拠を発見しましたが、このマージンはそれを含めるには小さすぎます...

確かに、これはここで起こっていることを解決するための唯一の方法であり、おそらく他にも多くの方法があります。

要約:TL; DR

  • タイプ「分化」は「穴をあける」に対応します。
  • ファンクタを適用すると、そのファンクタ0の「空のような」用語が得られます。
  • したがって、マクラウリンのべき級数は(ある程度)厳密に、特定の数の要素を持つファンクタータイプのメンバーの数を列挙することに対応しています。
  • 暗黙の微分により、これはより水密になります。
  • 導関数の一意性とべき級数の一意性は、詳細をいじることができ、機能することを意味します。

6

依存型理論と「任意の」型関数

この質問に対する私の最初の答えは、コンセプトは高く、詳細は低く、サブ質問「何が起こっているのか」に反映されました。この答えは同じですが、「任意の型関数を取得できますか?」というサブ質問に焦点を当てています。

sumとproductの代数演算の拡張機能の1つは、いわゆる「ラージオペレーター」です。これは、通常ΣΠそれぞれ記述されたシーケンスの合計と積(より一般的には、ドメイン上の関数の合計と積)を表します。Sigma Notationを参照してください。

だから合計

a + aX + aX² + ...

書かれるかもしれない

Σ[i  ℕ]aX

どこa実数のいくつかのシーケンスは、たとえば、あります。製品はのΠ代わりにと同様に表されΣます。

遠くから見ると、この種の式はの「任意」関数によく似ていXます。もちろん、表現可能なシリーズとそれに関連する分析機能に限定されています。これは型理論の表現の候補ですか?間違いなく!

これらの式を直接表現する型理論のクラスは、「依存型」型理論のクラス、つまり依存型の理論です。当然、用語に依存する用語があり、型関数と型の数量化を備えたHaskellのような言語では、型に依存する用語と型があります。依存する設定では、用語に応じてタイプを追加します。Haskellは依存型付き言語ではありませんが、依存型の多くの機能は、言語を少し拷問することでシミュレートできます。

カレーハワードと依存型

「カレーハワード同型」は、単純型付きラムダ計算の用語と型判定ルールが、命題の代わりに型を使用して、直観主義命題論理に適用された(Gentzenによって定式化された)自然演繹に正確に対応するという観察として誕生しました、および証明に代わる条件ですが、この2つは独立して発明/発見されました。それ以来、型理論家にとって大きなインスピレーションの源となっています。考慮すべき最も明白なことの1つは、命題論理のこの対応を述語またはより高次の論理に拡張できるかどうか、およびその方法です。依存型理論は当初、この探索の道から生まれました。

単純型付きラムダ計算のカリーハワード同型の紹介については、こちらを参照してください。例として、証明したい場合は証明して証明A ∧ Bする必要がAありBます。結合された証明は、単純に2つの証明の組み合わせです。

自然控除では:

Γ  A    Γ  B
Γ  A  B

そして単純に型付けされたラムダ計算では:

Γ  a : A    Γ  b : B
Γ  (a, b) : A × B

合計タイプ、関数タイプ、およびさまざまな消去規則についても、同様の対応が存在します。

証明できない(直観的には誤り)命題は、無人のタイプに対応します。

論理的な命題としての型の類比を念頭に置いて、型の世界で述語をモデル化する方法を検討し始めることができます。これが形式化された多くの方法があります(広く使用されている標準については、Martin-Löfの直観型理論の紹介を参照してください)。命題に条件をとる関数。型式に用語を含めることを許可すると、ラムダ計算スタイルでの処理がすぐに可能性として現れます。

建設的な証明のみを考慮して、何の証明を構成し∀x ∈ X.P(x)ますか?x対応する命題(P(x))の証明に条件()をとって、それを証明関数と考えることができます。したがって、型(命題)のメンバー(証明)∀x : X.P(x)は「依存関数」であり、それぞれxX型の項を与えP(x)ます。

どう∃x ∈ X.P(x)ですか?我々は、任意のメンバーを必要としXx一緒の証明で、P(x)。タイプ(命題)のメンバー(証明)ので∃x : X.P(x)区別用語:「依存ペア」でありxX、一緒に種類の用語とはP(x)

表記:使用します

x  X...

実際のクラスのメンバに関する声明についてX、および

x : X...

typeの普遍的な数量化に対応する型式の場合X。同様に

組み合わせに関する考慮事項:積と合計

命題を伴う型のカリーハワード対応だけでなく、この問題の主要な点である代数型と数値および関数との組み合わせ対応があります。幸いにも、これは上記の依存型に拡張できます!

モジュラス表記を使用します

|A|

型の「サイズ」を表現Aし、質問で概説されている型と数の間の対応を明確にする。これは理論外の概念であることに注意してください。言語内にそのような演算子が必要であるとは主張していません。

タイプの可能な(完全に削減された、正規の)メンバーを数えましょう

x : X.P(x)

これは、型の項xから型の項への依存関数Xの型P(x)です。そのような各関数は、のすべての項に対してX出力を持たなければならず、この出力は特定のタイプでなければなりません。それぞれの場合xX、それから、これは与え|P(x)|出力の「選択肢」を。

パンチラインは

|∀x : X.P(x)| = Π[x : X]|P(x)|

もちろん、これはの場合Xはあまり意味がありませんがIO ()、代数型に適用できます。

同様に、タイプの用語

x : X.P(x)

はとのペアのタイプであるため、のいずれかが与えられる(x, p)p : P(x)、の任意のメンバーと適切なペアを構築し、「選択肢」を与えることができます。xXP(x)|P(x)|

したがって、

|∃x : X.P(x)| = Σ[x : X]|P(x)|

同じ警告で。

これは、記号Πとを使用する理論の依存型の一般的な表記を正当化します。Σ実際、多くの理論は、上記の対応により、「すべて」と「製品」と「あり」と「合計」の区別を曖昧にします。

間近です!

ベクトル:従属タプルを表す

次のような数値式をエンコードできますか

Σ[n  ℕ]X

型式として?

結構です。XⁿHaskellのように式の意味を非公式に検討することはできますXが、は型とn自然数ですが、これは表記法の乱用です。これは数値を含む型式です。明らかに有効な式ではありません

一方、図の依存型では、数値を含む型がまさにポイントです。実際、依存タプルまたは「ベクター」は、依存型がリストアクセスなどの操作に実用的な型レベルの安全性を提供する方法の非常に一般的に引用される例です。ベクトルは、長さに関する型レベルの情報を含む単なるリストです。正確には、のような型式の後に何があるかXⁿです。

この回答の期間中、

Vec X n

-type値のlength- nvectorのXタイプです。

技術的nには、実際の自然数ではなく、自然数のシステムでの表現です。我々は(自然数を表すことができNat、ゼロ(としてペアノのスタイルで)0)、またはその後継(Sのために別の自然数の)、そしてn ∈ ℕ私が書く˻n˼に用語を意味するようにNat表しているがn。たとえば˻3˼ですS (S (S 0))

次に、

|Vec X ˻n˼| = |X|ⁿ

どれでもn ∈ ℕ

NATタイプ:タイプへのℕ用語の昇格

これで、次のような式をエンコードできます

Σ[n  ℕ]X

タイプとして。この特定の式はX、質問で特定されているように、もちろんのリストのタイプに同型のタイプを生成します。(それだけでなく、カテゴリ理論の観点から、タイプ関数-ファンクタである- X上記のタイプを採用することは、当然リストファンクタと同型です。)

「任意の」関数のパズルの最後のピースは、エンコードする方法です。

f :   

のような表現

Σ[n  ℕ]f(n)X

べき級数に任意の係数を適用できるようにします。

代数型と数値の対応はすでに理解しているため、型から数値へ、型関数から数値関数へのマッピングが可能です。他の方法で行くこともできます!-自然数を取ると、依存型があるかどうかに関係なく、明らかにその数の項メンバーを持つ定義可能な代数型があります。型理論のでこれを帰納法によって簡単に証明できます。システム内で、自然数から型にマッピングする方法が必要です。

満足のいく実現は、依存型があると、帰納法による証明と再帰による構築が密接に類似することになります-実際、それらは多くの理論で非常に同じものです。誘導によって、ニーズを満たす型が存在することを証明できるので、それらを構築できないのでしょうか。

用語レベルでタイプを表す方法はいくつかあります。ここでは*、型のユニバースについて、架空のHaskellish表記を使用します。それ自体は通常、従属設定の型と見なされます。1

同様に、依存型理論と同じように、少なくとも '-除去'を表記する方法もたくさんあります。ハスケリッシュのパターンマッチング表記法を使用します。

私たちは、マッピングを必要とするαからNat*プロパティを使用して、

n  ℕ.|α ˻n˼| = n.

次の疑似定義で十分です。

data Zero -- empty type
data Successor a = Z | Suc a -- Successor ≅ Maybe

α : Nat -> *
α 0 = Zero
α (S n) = Successor  n)

したがって、のアクションはα後続のの動作をSミラーリングし、一種の準同型になります。Successor型のメンバーの数に「1」を追加する型関数です。つまり、サイズが定義さ|Successor a| = 1 + |a|れているすべてのa場合です。

たとえばα ˻4˼(つまりα (S (S (S (S 0)))))は、

Successor (Successor (Successor (Successor Zero)))

このタイプの条件は

Z
Suc Z
Suc (Suc Z)
Suc (Suc (Suc Z))

正確に4つの要素を提供します|α ˻4˼| = 4

同様に、についてはn ∈ ℕ

 ˻n˼| = n

要求に応じ。

  1. 多くの理論では、のメンバーは*タイプの単なる代表である必要があり、操作はタイプの用語から*関連するタイプへの明示的なマッピングとして提供されます。他の理論では、リテラルタイプ自体を用語レベルのエンティティにすることができます。

「任意」の機能?

完全に一般的なパワーシリーズをタイプとして表現するための装置が用意されました。

シリーズ

Σ[n  ℕ]f(n)X

タイプになります

n : Nat f˼ n) × (Vec X n)

どこ˻f˼ : Nat → Nat機能の言語内のいくつかの適切な表現ですf。これは次のように見ることができます。

|∃n : Nat f˼ n) × (Vec X n)|
    = Σ[n : Nat]|α f˼ n) × (Vec X n)|          (property of  types)
    = Σ[n  ℕ]|α f˼ ˻n˼) × (Vec X ˻n˼)|        (switching Nat for ℕ)
    = Σ[n  ℕ]|α ˻f(n × (Vec X ˻n˼)|           (applying ˻f˼ to ˻n˼)
    = Σ[n  ℕ]|α ˻f(n)˼||Vec X ˻n˼|              (splitting product)
    = Σ[n  ℕ]f(n)|X|ⁿ                           (properties of α and Vec)

これはどれだけ「恣意的」なのでしょうか?この方法による整数係数だけでなく、自然数にも制限されます。それとは別に、依存型のチューリング完全言語がf与えられれば、何でもかまいませんが、自然数係数で任意の分析関数を表すことができます。

私はこれと、このList X ≅ 1/(1 - X)ような否定的で非整数的な「型」がこの文脈で持つ可能性のある疑問やどのような意味を持つ可能性があるかなどとの相互作用を調査していません。

うまくいけば、この答えは、任意の型関数でどこまで行けるかを調査するのに役立つでしょう。

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