I'm having trouble understanding how this Haskell expression works:
import Control.Monad
import System.IO
(forM_ [stdout, stderr] . flip hPutStrLn) "hello world"
What is the . flip hPutStrLn
part doing exactly? The type signatures seem complicated:
ghci> :type flip
flip :: (a -> b -> c) -> b -> a -> c
ghci> :type (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
ghci> :type (. flip)
(. flip) :: ((b -> a -> c1) -> c) -> (a -> b -> c1) -> c
ghci> :type (. flip hPutStrLn)
(. flip hPutStrLn) :: ((Handle -> IO ()) -> c) -> String -> c
What becomes the left and right operands of the (.)
operator as the expression is evaluated?
Another way to putting my question is, how does the left part of the expression at the top end up with a type signature like this:
(forM_ [stdout, stderr] . flip hPutStrLn) :: String -> IO ()