アプリカティブファンクター
ファンクターの関数適用
アプリカティブファンクターの前にファンクターの関数適用について。
今までは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
リンク
リンク