パラメトリシティを使って自由モノイドが構成できることの証明
目的
この記事では、以下のように定義したFM
が、一定の条件のもとで自由モノイドになっていることをパラメトリシティを使って証明したい。
動機としては、https://qiita.com/lotz/items/424abee02fe598c60247 のコメント欄における$\bar f$の一意性についての議論に答えを出したかった。
{-# LANGUAGE RankNTypes #-}
module FM where
newtype FM a = FM { runFM :: forall m. (Monoid m) => (a -> m) -> m }
instance Semigroup (FM a) where
FM a <> FM b = FM (\k -> a k <> b k)
instance Monoid (FM a) where
mempty = FM (\_ -> mempty)
embed :: a -> FM a
embed x = FM (\k -> k x)
foldMap :: (Monoid m) => (a -> m) -> FM a -> m
foldMap f (FM g) = g f
前提条件
以下を仮定する。
- Free theoremが成立するようなHaskellのサブセットで考える。具体的には、
seq
と⊥については考慮しない。 - 関数の外延性を仮定する。つまり、同じ引数に対して同じ値を返す関数は、実行効率などの点で違いがあっても、同じとみなす。
また、証明の中ではnewtype
を付けたり外したりする関数FM
とunFM
を省略して書く。
命題0
foldMap f
はモノイド準同型である。
証明
定義を展開すれば分かる。
命題1
f
が関数で、u
がモノイド準同型であるとき、
foldMap (u . f) = u . foldMap f
証明
型forall m. (Monoid m) => (a -> m) -> m
についてのfree theoremを計算すると、この型の項t
は以下の性質を満たすことが分かる。
任意の関数fと、任意のmemptyと(<>)を保存する関数uについて、t (u . f) = u . t f
ただし、「u
がmempty
と(<>)
を保存する関数である」とは、任意のa
、b
について以下が成り立つことである。
u mempty = mempty
u (a <> b) = u a <> u b
u
はモノイド準同型だから、mempty
と(<>)
を保存する。foldMap
の定義を使うと、示すべき命題が示される。
命題2
任意のf
について、
foldMap f . embed = f
証明
定義を展開すれば分かる。
命題3
foldMap embed = id
証明
foldMap embed g f
を変形していく。
foldMap embed g f
= {foldMapの定義を逆向きに使う}
foldMap f (foldMap embed g)
= {命題1を内側のfoldMapに適用する。命題0よりこれは許される}
foldMap (foldMap f . embed) g
= {命題2}
foldMap f g
= {foldMapの定義}
g f
外延性の仮定から、foldMap embed = id
がいえる。
命題4
FM a
はa
をアルファベットとする自由モノイドである。
証明
「任意のf
について、h . embed = f
を満たすモノイド準同型h
が唯一つ存在する」を示せばよい。
このようなh
が存在して、foldMap f
で与えらえることは命題2と命題0から分かる。
次に一意性を示す。このようなh
が他にも存在したとすると、
foldMap f
= {仮定より}
foldMap (h . embed)
= {命題1}
h . foldMap embed
= {命題3}
h
従って、このようなh
は全てfoldMap f
に等しく、よって一意である。これで証明できた。