前回の続きです。
前回のまとめ
前回の記事と同様に、R, P, RP
を以下のモナドとします。
type P = Maybe -- Pointed の P
type R x = A -> x -- Reader の R
type RP x = A -> Maybe x
前回は、モナドRP x = MaybeT (Reader A) x = A -> Maybe x
が持つ特別な性質として、
- モナド
T
とモナド準同型r :: R ~> T
とp :: P ~> T
が与えられたとき、rp = join . fmap p . r :: RP ~> T
もモナド準同型である r
が単射であれば、上述のrp
も単射である
ことを示しました。また、これを用いれば、一部のモナドT
の性質に関する証明が簡単になることがわかりました。
一方で、
といった証明に使うには、単射rp
を持つだけでは不十分でした。
これらの証明は、「ある方法で構成したリストの長さが必ずn
で、しかも長さn
の任意のリストを構成できる」
「特定のコンストラクタがちょうどn
個の引数をとる」
といった類の事実を発見することで行っていました。
こういった性質をアドホックに定式化するならば、例えば次のようなかたちを取るでしょう。
「ある自然変換
f :: (N -> a) -> [a]
は、長さがちょうど|N|のリストへの同型になっている」ことを、 「リスト関手を長さが|N|のリストとそれ以外の長さのリストに分割する自然同型split_N, unsplit_N
が存在して、f = unsplit_N . Left
」と表現する-- @unsplit_N@ は @split_N@ の逆 split_N :: [a] -> Either (N -> a) (ListButN a) unsplit_N :: Either (N -> a) (ListButN a) -> [a]
「関手
G
は、ある自然変換f :: (N -> a) -> G a
を持っており、これは『|N|引数のコンストラクタ』とみなせる」を、 リストの場合と同様に、「ある自然同型split_N, unsplit_N
があり、f = unsplit_N . Left
であること」と表現するsplit_N :: G a -> Either (N -> a) (G_ButN a) unsplit_N :: Either (N -> a) (G_ButN a) -> G a
より一般に、ある自然変換f
が、関手F
を関手G
の「直和成分」にすること、すなわち以下のように定式化することが考えられます。
自然変換
f :: F a -> G a
は、G
をF
とG_minus_F
の和に分解するような自然同型split :: G a -> Either (F a) (G_minus_F a) unsplit :: Either (F a) (G_minus_F a) -> G a
を使って、
f = unsplit . Left
と書ける
しかし、この定式化はいくつかの点で望ましくありません。
- 自然変換の値域になる関手とならない関手に分けるという操作が煩雑であり、証明の見通しが良くならなかった
- そもそも、「自然変換の値域にならない関手」が定義できないことがある。例えば、
F x = (Integer -> Integer, x)
という関手においてf a = (id, a)
の値域にならないもの、という関手を作るには、Integer -> Integer
からid
の一点だけを除いた型が必要になるが、そのような型はない。
そのため、こうした問題を迂回できるような、よい定式化を探しました。 そこで見つけたのがequifibered自然変換です。
Equifibered自然変換
定義
Equifibered自然変換(equifibered natural transformation - nLab)とは、
関手F, G
間の自然変換 τ :: ∀a. F a -> G a
であって、任意の型a, b
と関数f :: a -> b
に対して、以下の条件を満たすものです。
τ
の自然性を表す以下の可換図式は引き戻しであるfmap f F a --------> F b | | | τ | τ | | v fmap f v G a --------> G b
これは、Haskell
のFunctor
間の自然変換に限れば、次のように言い換えることができます。
- 任意の
f :: a -> b
,x :: F b
とy :: G a
でτ x = fmap f y :: G b
を満たすものがあれば、 あるv :: F a
が存在してx = fmap f v
かつy = τ v
を満たす。 また、この条件を満たすv
は唯一つに定まる。
このx :: F b
とy :: G a
に対して唯一定まるv :: F a
のことを、「f :: a -> b
に沿って
x
をy
に引き戻した値」と呼ぶことにします。
Equifibered自然変換の例
Equifibered自然変換の具体例を考えます。F
がただ値を2つ保持する関手、G
をリスト関手とします。
data F a = F a a
type G a = [a]
以下の自然変換ok
とok'
はequifiberedですが、bad
とbad'
はequifiberedではありません。
bad' :: F a -> G a
ok, ok', bad,F a1 a2) = [a1, a2]
ok (F a1 a2) = [a2, a1]
ok' (
F a1 a2) = [a1]
bad (F a1 a2) = [a1, a1, a2, a2] bad' (
x = F b1 b2 :: F b
が任意に与えられているとき、y :: [a]
がok x = fmap f y
を満たしたとします。fmap
はリストの長さを変えないので、y = [a1, a2]
でしかありえません。更に、= ok (F b1 b2) = [b1, b2] = ok x fmap f y = fmap f [a1, a2] = [f a1, f a2]
なので、
f a1 = b1, f a2 = b2
が成り立っています。したがって、v = F a1 a2
とすれば、fmap f v = x, ok v = y
が成り立ちます。ok'
も同様です。y = [a1, a2]
のとき、ただ順序を入れ替えてv = F x2 x1
とすれば、fmap f v = x, ok v = y
が成り立ちます。bad
はF
に含まれている情報を捨ててしまいます。= F b1 b2 x = [a1] y = [b1] = bad' x fmap f y = [f a1]
すなわち
f a1 = b1
であることだけがわかります。v = F a1 a2
のうち、fmap f v = x
すなわちf a2 = b2
であるようなa2
が唯一存在すればよかったのですが、f
は任意の関数であるため、f a2 = b2
を満たすa2
が一つもないこともあれば複数あって一意に定まらないこともあります。そのため、
bad
はequifiberedではありません。bad'
は単射自然変換ではあるので、少なくともx
に関する情報を消してしまうことはありません。y
は長さ4のリストだとわかっています。しかし、= F b1 b2 x = [a1, a2, a3, a4] y = [b1, b1, b2, b2] = bad' x fmap f y = [f a1, f a2, f a3, f a4]
が成り立ちながら
a1 /= a2, a3 /= a4
であることは十分あり得るにもかかわらず、bad'
の値域はつねに1番目と2番目、3番目と4番目の要素が等しいため、bad' v = y
が成り立つv
は存在しないことがあります。したがって、
bad'
はequifiberedではありません。
こういった例からわかるように、リストのような多項式関手の場合は、
τ :: (N -> a) -> G a
がequifibered自然変換 ⇔G
はτ
の値域とそれ以外の直和に分けることができ、 値域に対してはτ
は同型 1τ :: F a -> G a
がequifibered自然変換かつ単射 ⇔F
はτ
の値域とそれ以外の直和に分けることができ、 値域に対してはτ
は同型
となります。
r
がequifiberedならばrp
もequifibered
モナドT
とモナド準同型r :: R ~> T
とp :: P ~> T
が与えられたとき、
「r
がequifiberedモナド準同型であればrp
もそうである」ことを証明します。
証明には、前回の記事で用いた補助的な関数や等式を使います。
まず、refill, mask
という関数を以下のように定義していました。
zero :: T a
= p Nothing
zero
refill :: T a -> R Bool -> T (P a)
= join . r $ \i ->
refill ta cond if cond i then fmap Just ta else pure Nothing
mask :: T a -> R Bool -> T a
= join . fmap p $ refill ta cond mask ta cond
前回の記事では、これらの関数について、以下の等式を証明しました。
- (Eq3)
-
. x) = r x refill (rp x) (isJust
mask
は以下のように書くこともできます。
- (Eq4)
-
= join . r $ \i -> if cond i then y else zero mask y cond
証明
mask y cond= join . fmap p . join . r $ \i ->
if cond i then fmap Just y else pure Nothing
= join . r . fmap (join . fmap p) $ \i ->
if cond i then fmap Just y else pure Nothing
= join . r $ \i ->
if cond i then (join . fmap p . fmap Just) y
else (join . fmap p . pure) Nothing
= join . r $ \i ->
if cond i then (join . fmap pure) y
else (join . pure . p) Nothing
= join . r $ \i -> if cond i then y else zero
-- (*)
. fmap p . join . r
join = join . join . fmap (fmap p) . r
= join . fmap join . fmap (fmap p) . r
= join . r . fmap (join . fmap p)
任意のxb :: R (P b), ya :: T a
に対して、rp xb = fmap f ya
が成り立っているならば、
あるxa :: R (P a)
が存在してrp xa = ya, fmap (fmap f) xa = xb
となること、
及びそのようなxa
が唯一であることを示します。
まず、そのようなxa
が存在すれば唯一であることを示します。
次の値za
を考えます。
za :: T (Maybe a)
= refill ya (isJust . xb) za
ここでfmap (fmap f) za = r xb
です。
fmap (fmap f) za
= fmap (fmap f) (refill ya (isJust . xb))
-- 自然性
= refill (fmap f ya) (isJust . xb)
-- 仮定より fmap f ya = rp xb
= refill (rp xb) (isJust . xb)
-- (Eq3)
= r xb
いま、任意のxa :: R (P a)
について、仮にrp xa = ya
かつfmap (fmap f) xa = xb
が成り立っているとすると、
(Eq3)よりr xa = refill (rp xa) (isJust . xa) = refill ya (isJust . xb) = za
です。
これは、equifibered自然変換r :: R ~> T
の下、 xa
が fmap f :: P a -> P b
に沿って
xb :: T (P a)
を za :: T (P a)
に引き戻した値であることを意味します。
そのため、このようなxa
は存在すれば唯一です。
逆に、xa :: R (P a)
を、fmap f
に沿って xb
を za
に引き戻した値とします。
すなわち、r xa = za
かつ fmap (fmap f) xa = xb
を満たす唯一の値だとします。
このとき、rp xa = ya
が成り立ちます。すなわち、xa
は f :: a -> b
に沿って
xb :: R (P b)
を ya :: T a
に引き戻した値になります。
rp xa= join . fmap p . r $ xa
= join . fmap p $ za
= join . fmap p $ refill ya (isJust . xb)
= mask ya (isJust . xb)
-- from (Eq4)
= join . r $ \i ->
if isJust (xb i) then ya else zero
-- from (**)
= join . r $ \i ->
if isJust (xb i) then ya
else mask ya (not . isJust . xb)
-- from (Eq4)
= join . r $ \i ->
if isJust (xb i)
then ya
else join . r $ \j -> if (not . isJust . xb) j then ya else zero
= join . r $ \i ->
if isJust (xb i)
then join . r $ const ya
else join . r $ \j -> if isJust (xb j) then zero else ya
= join . r . fmap (join . r) $ \i ->
if isJust (xb i)
then const ya
else \j -> if isJust (xb j) then zero else ya
-- from (***)
= join . r . join $ \i ->
if isJust (xb i)
then \_ -> ya
else \j -> if isJust (xb j) then zero else ya
= join . r $ const ya
= ya
-- (**)
fmap f (mask ya (not . isJust . xb)
= mask (fmap f ya) (not . isJust . xb)
= mask (rp xb) (not . isJust . xb)
= zero
not . isJust . xb) = zero
mask ya (
-- (***)
. r . fmap (join . r)
join = join . fmap join . r . fmap r
= join . join . r . fmap r
= join . r . join
Equifiberedを使ってわかること
この系として、面倒な等式変形を要した以下の2つの定理が得られます。
定数でない多項式Functor
F
で、“次数”が1の項を持たず、かつ”定数項”を持つようなもの、 すなわちF(x) = c + x^2 * G(x)
と書けるようなものには、Monad
のインスタンスが存在しない。 (過去の記事)F
のMonad
のインスタンスを仮定すれば、ある有限な型N
(|N| ≥ 2)が存在して equifiberedなモナド準同型r :: (N -> x) -> F x
と、単射なモナド準同型p :: Maybe x -> F x
をとることができる。 このときrp = coprod r p :: (N -> Maybe x) -> F x
も単射かつequifiberedである。 したがって、F x
はrp
の値域(1 + x)^N
とそれ以外との直和F(x) = (1 + x)^N + H(x)
として書かれる。しかし、F(x)
は次数が1の項を持たなかったはずなので、これは矛盾である。すなわち、
F
はMonad
のインスタンスを持てない。リスト関手
[]
に対するMonad
のインスタンスとして、可能なpure :: x -> [x]
の選択肢はpure x = [x]
のみである。 ( @1to100pen 氏による証明 ) 特に、ZipList
と同様にrepeat :: x -> [x]
をpure
として用いるMonad []
のインスタンスはない2。pure x = []
ではありえないことはすぐにわかる。length (pure x) = N > 0
とおくと、 上記と同様に、単射かつequifiberedなモナド準同型rp :: (N -> Maybe x) -> [x]
を持たなければならない。 これによって、[x] = 1 + x + x^2 + x^3 + ...
は[x] = (1+x)^N + G(x)
と書けなければならない。 この分解が成り立つN
はN=1
に限られる。
F a = (N -> a)
であるときは、自然変換τ :: F a -> G a
がequifiberedならば単射です。 一般にはこれは言えません。例えば、F a = (Bool, N -> a), G a = (N -> a)
としたとき、snd :: F a -> G a
はequifiberedになります。 また、逆も成り立ちません。equifiberedにならない例として挙げたbad'
のように、 単射であってequifiberedでないことがあります。↩︎この弱い主張の証明を、Twitter上のやりとりで(Gist, @lysxia 氏によるCoqでの形式化)行っていたところ、 1to100pen 氏本人からより強い主張ができている上記Qiita記事を教えていただきました。
これが今回の記事の大きなモチベーションになっています。↩︎