Maybeの自作ですが、前回に引き続きApplicative型クラスの実装を追加してみました。 コードは次のとおり。
import Control.Applicative data Option a = None | Some a deriving (Eq, Show) instance Functor Option where fmap f (Some x) = Some (f x) fmap f None = None instance Applicative Option where pure = Some None <*> _ = None Some f <*> other = fmap f other getOrElse :: Option a -> a -> a getOrElse None v = v getOrElse (Some x) _ = x main = do let op1 = Some (*2) <*> Some (2) -- 4 let op2 = pure (*2) <*> Some (2) -- 4 let op3 = (*2) <$> Some (2) -- 4 let op4 = Some (*2) <*> None -- None let op5 = None <*> Some (2) :: Option Int -- None let op6 = (+) <$> Some (1) <*> Some (2) -- 3 print (op1, op2, op3, op4, op5, op6)
Applicativeの定義は次のとおり。(Functor f) =>
はfはFunctorだよと制約を宣言しているらしい。んで、pureと<*>関数を実装するだけらしい。
class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
op1はSome f <*> other = fmap f other
の実装が読めればさほど難しくない。op2もだいたい想像つく。
op3とop2は意味は同じだけ記述形式が違う。
pure f <*> x = fmap f x
という法則があるらしく、pure (*2) <*> Some (2)
はfmap (*2) Some (2)
に書き換えれるらしい。
pure (+) <*> Just 1 <*> Just 1
なら
fmap (+) (Just 1) <*> Just 1
に書き換えれる。fmap f xはよく使うのでApplicativeでは
f <$> x = fmap f x
と定義されているので、
(+) <$> Just 1 <*> Just 1
このように書くんだそうだ。
リストやIOもApplicativeなんですが、とりあえずこんなもんで。
追記:
let op5 = None <*> Some (2) :: Option Int
の部分の、:: Option Int の記述。これは型アノテーションかな? None <*> anyの場合は型推論がきかないそうで、こういう記述しないといけないらしい。ゆろよろせんせー ご指摘ありがとうございました。