haskellのApplicative laws - composition
こんにちは。
すごいHaskellたのしく学ぼう!の11章に出てくるアプリカティブ則の一つ、「composition則」について何を言っているかを考えてみました。
composition則
Applicative型クラスを継承するデータ型は、関数を実装すること以外にも、実装した関数が満たさなければいけない規則が存在します。これを確認するのは設計者に委ねられています。Applicative型クラスでは4つの法則が存在します。ここではその4つのうちの一つ「composition則」(正式名称不明)について考えてみたいと思います。ちなみに4つの法則はBasic libraries
のリファレンスControl.Applicativeのページに載っています。
「composition則」は次で定義されています;
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
なぜこの法則を満たさなければいけないのでしょうか。ここでは関数合成に対して、「アプリカティブファンクターに包まれた合成演算子(.)
を使って関数合成を行うことと、<*>
を使って関数合成を行うことは同じか?」ということが成り立って欲しいようです。単なる想像ですが、既存に存在している合成演算子(.)
と新しい合成演算子<*>
の間にある種の整合性を保っておきたいように見えます。composition則はそのことを確かめましょう、といっています。
composition則の定義を見ると、左辺がごちゃごちゃしています。適応の順を整理していきましょう。
pure (.) <*> u <*> v <*> w -- = ( pure (.) ) <*> u <*> v <*> w -- = ( ( pure (.) ) <*> u ) <*> v <*> w -- = ( ( ( pure (.) ) <*> u ) <*> v ) <*> w :
実際に適用して行ってみましょう。
-- u, v は以下; -- u :: Num a => Maybe (a -> a) -- v :: Num a => Maybe (a -> a) ghci>:t pure (.) pure (.) :: Applicative f => f ((b -> c) -> (a -> b) -> a -> c) -- まず合成演算子(.)がpureによってアプリカティブファンクターに包まれます。 ghci>:t pure (.) <*> u pure (.) <*> u :: Num c => Maybe ((a -> c) -> a -> c) -- 次に<*>で、アプリカティブファンクターに包まれた合成演算子の、 -- 第一引数の関数としてuを渡します。 ghci>:t pure (.) <*> u <*> v pure (.) <*> u <*> v :: Num c => Maybe (c -> c) -- 再び<*>で、アプリカティブファンクターに包まれた合成演算子の、 -- 第二引数の関数としてvを渡します。 ghci>:t pure (.) <*> u <*> v <*> Just 1 pure (.) <*> u <*> v <*> Just 1 :: Num b => Maybe b -- 最後に完成したアプリカティブファンクターに包まれた関数に対し、 -- <*>でアプリカティブ値を渡します。
左辺はこれで終わりです。右辺は<*>
で関数適用をチェインしているだけなので割愛です。
なぜ必要なのか?
これに関してははっきりとしたことはわかりませんでした。composition則が何を保証したいかは、結合演算子がどんな関数にも使えることに関係してくるのではないかと思うのですが自信はないです。調べたいと思います。