このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

zipが自然変換だという話

zipと言っても、圧縮&アーカイブのツールではありません。リスト処理の話です。ファスナーをしめる操作を連想させるのでzipと呼ぶのでしょう。今ここでは、「あのzipです」という以上の説明はしません。あのzipを型付けすると、自然変換だと解釈できます。二項関手のあいだの自然変換なので、モナド(の台関手)などとは違った雰囲気のものです。


集合圏の小さい部分圏Cを固定して、ここを舞台に考えます。C内で直積や直和は自由に作れるとします。もうひとつの圏Dがあるとして、F:DC が関手のとき、Fの対象部分(object part)をF0、射部分(morphism part)をF1とします。さらに、射部分は対象の対ごとに分割して F1A,B:D(A, B)→C(F0(A), F0(B)) のようにも書きます。関手Fは、写像F0:|D|→|C| と (A, B)∈(|D|×|D|) で添字付けられた写像の族 F1A,B:D(A, B)→C(F0(A), F0(B)) として記述できます。

L:CC はリスト関手とします。A∈|C| (Aは集合)に対して、L0(A) はAの要素を項目とするリストの全体です。f:A→B に対する L1A,B(f):L0(A)→L0(B) はリストのmap高階関数のことです。L(f) = L1A,B(f) は、リストの各項目にfを適用したリストを作ります。

P:C×CC は、ペアリング関手とします。Pは二項関手(双関手)となります。二項関手の定義域は圏Cの(直積の意味での)二乗です。C×CDと置くと、Dの対象は (A, B)∈|C|×|C| という対で、D((A, B), (C, D)) に入る射は f:A→C in C と g:B→D in C の対 (f, g) です。ペアリング関手Pを詳しく書くと:

  • P0:|C|×|C|→|C|, P0(A, B) = A×B
  • P1(A,B),(C,D):(C×C)((A, B), (C, D)) = C(A, C)×C(B, D) →C(A×B, C×D), P(f, g) = f×g

f×g をより具体的に言えば:

  • f×g:A×B→C×D
  • (a, b)∈(A×B) に対して、(f×g)(a, b) = (f(a), g(b))。(f(a), g(b))∈(C×D)。

f×g とデカルトペアリング <f, g> は区別してください。<f, g>(a) = (f(a), g(a)) です。

さて、L:CC と P:C×CC という2つの関手が定義できました。LとPを組み合わせて、PLLを定義します。

  • PLL(A, B) = P(L(A), L(B)) : |C|×|C|→|C|
  • PLL(A,B),(C,D)(f, g) = P(L(f), L(g)) : (C×C)((A, B), (C, D))→C(PLL(A, B), PLL(C, D))

上付きの0と1は省略しました。同様に、LPを次のように定義します。

  • LP(A, B) = L(P(A, B)) : |C|×|C|→|C|
  • LP(A,B),(C,D)(f, g) = L(P(f, g)) : (C×C)((A, B), (C, D))→C(LP(A, B), LP(C, D))

ふー、これで準備ができました。

zipは、関手PLLから関手LPへの自然変換です。つまり、zip::PLL⇒LP:C×CC と書けます。zipは、|C|×|C| の要素(A, B)で添字付けられた写像の族 zipA,B:PLL(A, B)→LP(A, B) として表現されます。実際のリスト処理のzipがそのような多相関数になっていることを確認してみてください。

zipが自然性を持つとは、次の図式が可換になることです。これも具体的に確認できます。

PLL(A, B) - zip_(A,B) → LP(A, B)
|                       |
PLL(f, g)               LP(f, g)
↓                       ↓
PLL(C, D) - zip_(C,D) → LP(C, D)