読者です 読者をやめる 読者になる 読者になる

かとじゅんの技術日誌

技術の話をするところ

Maybeを自作してみる(Applicative編)

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の場合は型推論がきかないそうで、こういう記述しないといけないらしい。ゆろよろせんせー ご指摘ありがとうございました。