きっかけは、先月Qiitaに投稿された次の記事を読んだことです。
HaskellにおけるFunctor => Applicative => Monadの継承関係についての考察記事ですが、これを圏論的な視点からアプローチしなおしてみようと思ったのが当初の目的でした。しかし、そのために調べ物をしていると、あまりにも自分がapplicative functorについて知らないということが発覚してしまい、記事の内容を大幅に変更したものが本記事です。
本記事ではHaskellにおけるFunctorが果たす役割を圏論的なアプローチで考察します。 Haskell Advent Calendar に参加しようとも思っていたのですが、土壇場で熱を出して数日寝込んだために全ての予定が四散してしまいました。南無。
本記事では圏論の以下の知識を前提として書いていきます。これら基礎知識については Leinster や Mac Lane の対応する章、あるいは alg-dさんの圏論のページ などをご参照ください。
また、例示部分に限ってはさらに追加の知識が必要になるかもしれません。ご了承ください。もしいい例をご存じの方がいましたらご教示いただけると幸いです。
型 (の組)、あるいはその型の値の集合を対象として、変数の組
型とプログラムで圏を構成できるということは、型付きのプログラムを行う体系は圏論によって抽象的な議論が可能ということになります。あるいは、圏論を通して意味論を様々考えることができるようにもなります。
一般的なラムダ計算の体系において、その圏論的意味論にはカルテシアン閉圏が採用されます。カルテシアン閉圏とは、終対象
Haskellで言うと、終対象とは
HaskellにおけるFunctorとは、型演算
可換モノイドとその間のモノイド準同型からなる圏
任意の可換モノイド
で定める。
このとき、モノイド準同型
で定まり、
一方で、
対称モノイダル閉圏
すなわち、強自己関手
の組であり、次の2つの図式を可換にするものである:
ここで
本稿ではモノイダル圏や豊穣圏については立ち入らず、強自己関手の定義も後半の言い換えたものを使います。カルテシアン閉圏は対称モノイダル閉圏の特別な場合なので、以降カルテシアン閉圏と直積で書きます。モノイダル圏や豊穣圏についてどうしても気になる場合は、以下の文献を参考にしてください。
圏
逆に、上記の2つの図式を可換にする
ここで
実は、定義2の図式を可換にする
Const
型はConst a b = Const { getConst :: a }
で定義されるデータ型です。この型についての説明には
The 'Const' functor.
とあり、本質的には型aの値を保持したままFunctorのように振る舞う存在であると思われます。実際、Functorのインスタンスが次のように実装されます:
instance Functor (Const a) where
fmap _ (Const v) = Const v
Const aはaがMonoidのインスタンスである場合のみApplicativeのインスタンスが実装されています。これは、型Const a (x -> y)の値と型Const a xの値から型Const a yの値を作るに際して、それぞれの値が持つ型aのデータの処理を、Applicativeの公理を満たしながら行うことができないためと思われます。
強関手は関手よりは強い概念ですが、プログラミングの上では基礎的な構造以上の有用性を持っていません。具体的には
そのような計算を保証した構造が、HaskellのApplicative、圏論ではapplicative functorと呼ばれるものです。