こういうところやこういうところでよく見るのですが、全くわからずにコピペして使ってきました。
この辺りにわかり易い説明があります。
qiitaの記事
お気楽Haskellプログラミング入門の記事
pure
と<*>
は、Control.Applicativeのメソッドです。<$>
あるいはfmap
は、Data.Functorのメソッドです。<$>
はfmap
の中置演算子版、要するに同じ関数です。
pure
は、任意のデータを取ってApplicativeに持ち上げ(lift)ます。値でも関数でも構いません。
pure :: a -> f a
-- 例
>>> :t pure 1
pure 1 :: (Applicative f, Num a) => f a
>>> :t pure True
pure True :: Applicative f => f Bool
>>> :t pure (+2)
pure (+2) :: (Applicative f, Num a) => f (a -> a)
>>> :t pure (+)
pure (+) :: (Applicative f, Num a) => f (a -> a -> a)
>>> :t pure words
pure words :: Applicative f => f (String -> [String])
<*>
は、Applicativeの中の値に対して関数を適用します。Applicativeに包まれた関数を第一引数にとり、Applicativeに包まれたデータを第二引数に取ります。
(<*>) :: f (a -> b) -> f a -> f b
例えば、Just 1
は、Maybe Int
型ですが、このIntをインクリメントしたい場合、以下のように書くかもしれません。
-- ghciで複数行定義をする場合も、インデントに気をつけて
Prelude> :set +m
Prelude> d = Just 1
Prelude> let d' = case d of
Prelude| Just v -> return (v+1)
Prelude| Nothing -> Nothing
Prelude|
Prelude> d'
Just 2
これを、<*>
を使うと、以下のように簡潔に書くことができます。
Prelude> let d'' = pure (+1) <*> d
Prelude> d''
Just 2
MaybeはApplicativeのインスタンスです。pure (+1)
で関数をApplicativeに持ち上げ、<*>
を使ってMaybe
の中の値に直接関数を適用することができるのです。もちろん、Nothing
に適用しても大丈夫です。
Prelude> pure (+1) <*> Nothing
Nothing
またこれは、<$>
を使うと以下のように書くこともできます。
(<$>) :: Functor f => (a -> b) -> f a -> f b
Prelude> let d''' = (+1) <$> d
Prelude|
Prelude> d'''
Just 2
<$>
は、関数をApplicativeの中のデータに適用します。見ての通り、<*>
と<$>
はとてもよく似ています。<*>
は第一引数がApplicativeなのに対し、<$>
は第一引数が通常の関数です。だから、(<*>) . pure
と<$>
はほとんど同じです。
Prelude> :t (<*>) . pure
(<*>) . pure :: Applicative f => (a -> b) -> f a -> f b
Prelude> :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
全く同じだと思ったのですが、型を見てみると、少し違いました。関数の働き方は同じですが、前者のf
はApplicativeで、後者はFunctorです。私はこの辺りのことがまだよくわかっていないので、説明できません。
Maybe
の例の場合は、Maybe
がApplicativeとFunctorの両方のインスタンスのため、全く同様に使うことができました。[]
やEither
やIO
なども全て、ApplicativeとFunctorの両方のインスタンスなので、上記の例と同じようなことができるはずです。
この辺りをちゃんと理解するには、Monad, Functor, Applicative, Monoidをまずわかっておく必要がありそうです。