Haskell アプリカティブファンクターの学習

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

アプリカティブファンクター

ファンクターの関数適用

アプリカティブファンクターの前にファンクターの関数適用について。

今まではfmap (*2) [1,2,3]のように引数に値を返す関数(*2)を定義していた。

これを

let a = fmap (*) [1,2,3]
ghci> :t a
a :: Num a => [a -> a]

とした場合、関数a->aが入ったファンクターが返ってくる。そして、このように

ghci> fmap (\func -> func 3) a 
[3,6,9]

とするとファンクター値が関数として渡され実行される。


Applicativeの定義

ApplicativeはFunctorのサブクラス型

class (Functor f) => Applicative f where
    pure :: a -> f a
    (<*>) :: f (a -> b) -> f a -> f b

pureは値をファンクターで包むメソッド。

<*>は先ほどの関数が入ったファンクターを引数にとりファンクター値に適用したメソッドと読める。

Maybeファンクターの定義をみて実行例をみれば分かり易い

instance Applicative Maybe where
  pure = Just
  Nothing <*> _ = Nothing
  (Just f) <*> something = fmap f something

以下のようにファンクターに入った関数が適用されている動きがわかる。

ghci> pure (+3) <*> Just 9
Just 12
ghci> pure (+3) <*> [1,2,3]
[4,5,6]
ghci> Just (+3) <*> Nothing
Nothing
ghci> Just (++"P") <*> Just "base"
Just "baseP"

pureが解釈するファンクターは右の引数から推測されているのがわかる。

そして、このようにアプリカティブメソッドをチェインすることができる。

ghci> pure (+) <*> Just 3 <*> Just 5
Just 8

この式は、

(pure (+<*> Just 3<*> Just 5

この式と同義。つまり()の中でファンクターに入った関数を返している。


<$>関数

<$>を使うことでファンクターの関数適用を簡略化できる。

(<$>) :: (Functor f) => (a -> b) -> f a -> f b
f <$> x = fmap f x
ghci> let b = (++) <$> Just "base"
ghci> b <*> Just "Add"
Just "baseAdd"
リストのアプリカティブインスタンス
ghci> [(*0),(+100),(^2)] <*> [1,2,3]
[0,0,0,101,102,103,1,4,9]


IOのアプリカティブインスタンス
main = do
  a <- (++<$> getLine <*> getLine


関数のアプリカティブインスタンス

(+3)と(*100)に引数5が適用され(+)が実行される

ghci> (+) <$> (+3) <*> (*100) $ 5
508