Ответ 1
TL; ДР:
writeFile <$> getFilename <*> getString >>= id :: IO ()
Моноды являются аппликативными
Так как ghc 7.10 каждая Монада (включая IO
) также является аппликативной, но даже до этого вы можете сделать аппликатор из любой Монады, используя эквивалент
import Control.Applicative -- not needed for ghc >= 7.10
instance Applicative M where
pure x = return x
mf <*> mx = do
f <- mf
x <- mx
return (f x)
И, конечно, IO
является функтором, но Control.Applicative
дает вам <$>
, который можно определить как f <$> mx = fmap f mx
.
Использование Применить для использования функций, которые принимают как можно больше аргументов
<$>
и <*>
позволяют использовать чистые функции f
по аргументам, созданным аппликативным/монадическим вычислением, поэтому, если f :: String -> String -> Bool
и getFileName, getString :: IO String
, то
f <$> getFileName <*> getString :: IO Bool
Аналогично, если g :: String -> String -> String -> Int
, то
g <$> getString <*> getString <*> getString :: IO Int
От IO (IO ())
до IO ()
Это означает, что
writeFile <$> getFilename <*> getString :: IO (IO ())
но вам нужно что-то типа IO ()
, а не IO (IO ())
, поэтому нам нужно либо использовать join :: Monad m => m (m a) -> m a
, как в Xeo comment, либо нам нужно чтобы взять монадический результат и запустить его, т.е. тип (IO ()) -> IO ()
, связать его с. Тогда это будет id
, поэтому мы можем либо сделать
join $ writeFile <$> getFilename <*> getString :: IO ()
или
writeFile <$> getFilename <*> getString >>= id :: IO ()