()は(.)の代わりに使える
例えばこういう関数群があったとして、
toStr :: Float -> String toStr = show length' :: String -> Int length' = length isBig :: Int -> Bool isBig = (> 5)
Haskellでは($)演算子を使ってデータに対して次々に関数を適用できる。
isBig $ length' $ toStr $ 32.1
($)演算子は右結合なので、以下のように結合している。
isBig $ (length' $ (toStr $ 32.1))
逆に、左結合を強制すると型が合わずにエラーになる。
((isBig $ length') $ toStr) $ 32.1 -- エラー
さて、関数に流し込みたいデータがFunctorの中に入っている場合、Control.Applicativeモジュールの(<$>)演算子が便利である。
isBig <$> length' <$> toStr <$> Just 32.1
しかし(<$>)演算子は左結合である。つまり以下のように結合していることになる。
((isBig <$> length') <$> toStr) <$> Just 32.1
しかも(<$>)演算子の場合、右結合を強制してもちゃんと動作する。
isBig <$> (length' <$> (toStr <$> Just 32.1))
なぜ($)と違って左結合で動作するのだろうか。
ここで、(isBig <$> length')の型を調べてみる。
*Main> :i isBig <$> length' isBig :: Int -> Bool -- Defined at ops.hs:11:1 (<$>) :: Functor f => (a -> b) -> f a -> f b -- Defined in `Data.Functor' infixl 4 <$> length' :: String -> Int -- Defined at ops.hs:8:1 *Main> :t isBig <$> length' isBig <$> length' :: String -> Bool
(<$>)の第2引数はlength'という関数である。そして関数はFunctorである。つまりこの場合、(<$>)は
(<$>) :: (Int -> Bool) -> (->) String Int -> (->) String Bool
このような型に束縛されていて、結果的に(String -> Bool)という型を返したのだ。
ちなみに上記の型を一般化すると以下のようになる。
(<$>) :: (b -> c) -> (->) a b -> (->) a c
これは関数合成演算子(.)と同じである。
*Main> :i (.) (.) :: (b -> c) -> (a -> b) -> a -> c -- Defined in `GHC.Base' infixr 9 .