Binding functions that take multiple arguments

前端 未结 3 1187
梦如初夏
梦如初夏 2021-01-01 17:03

After reading some very basic haskell now I know how to \"chain\" monadic actions using bind, like:

echo = getLine >>= putStrLn
相关标签:
3条回答
  • 2021-01-01 17:32

    This typechecks:

    import System.IO
    
    filepath :: IO FilePath
    filepath = undefined
    
    someString :: IO String
    someString = undefined
    
    testfun = filepath   >>= (\fp -> 
              someString >>= (\str -> 
              writeFile fp str  ))
    

    But I feel using do notation is more readable.

    0 讨论(0)
  • 2021-01-01 17:33

    TL;DR:

    writeFile <$> getFilename <*> getString >>= id   :: IO ()
    

    Monads are Applicative

    Since ghc 7.10 every Monad (including IO) is also an Applicative, but even before that, you could make an Applicative out of any Monad using the equivalent of

    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)
    

    And of course IO is a functor, but Control.Applicative gives you <$> which can be defined as f <$> mx = fmap f mx.

    Use Applicative to use functions that take as many arguments as you like

    <$> and <*> let you use pure functions f over arguments produced by an Applicative/Monadic computation, so if f :: String -> String -> Bool and getFileName, getString :: IO String then

    f <$> getFileName <*> getString :: IO Bool
    

    Similarly, if g :: String -> String -> String -> Int, then

    g <$> getString <*> getString <*> getString :: IO Int
    

    From IO (IO ()) to IO ()

    That means that

    writeFile <$> getFilename <*> getString :: IO (IO ())
    

    but you need something of type IO (), not IO (IO ()), so we need to either use join :: Monad m => m (m a) -> m a as in Xeo's comment, or we need a function to take the monadic result and run it, i.e. of type (IO ()) -> IO () to bind it with. That would be id then, so we can either do

    join $ writeFile <$> getFilename <*> getString :: IO ()
    

    or

    writeFile <$> getFilename <*> getString >>= id :: IO ()
    
    0 讨论(0)
  • 2021-01-01 17:43

    It's much easier to use do notation for this, rather than asking for a combinator

    action1 :: MyMonad a
    action2 :: MyMonad b
    f :: a -> b -> MyMonad c
    
    do
        x <- action1
        y <- action2
        f x y
    
    0 讨论(0)
提交回复
热议问题