Search code examples
stringfunctionhaskellfunctor

Haskell : concat two IO Strings


Today I have tried to concat two IO Strings and couldn't get it work.

So, the problem is: suppose we have s1 :: IO String and s2 :: IO String. How to implement function (+++) :: IO String -> IO String -> IO String, which works exactly as (++) :: [a] -> [a] -> [a] but for IO String?

And more general question is how to implement more general function (+++) :: IO a -> IO a -> IO a? Or maybe even more general?


Solution

  • You can use liftM2 from Control.Monad:

    liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
    
    
    > :t liftM2 (++)
    liftM2 (++) :: Monad m => m [a] -> m [a] -> m [a]
    

    Alternatively, you could use do notation:

    (+++) :: Monad m => m [a] -> m [a] -> m [a]
    ms1 +++ ms2 = do
        s1 <- ms1
        s2 <- ms2
        return $ s1 ++ s2
    

    Both of these are equivalent. In fact, the definition for liftM2 is implemented as

    liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
    liftM2 f m1 m2 = do
        val1 <- m1
        val2 <- m2
        return $ f val1 val2
    

    Very simple! All it does is extract the values from two monadic actions and apply a function of 2 arguments to them. This goes with the function liftM which performs this operation for a function of only one argument. Alternatively, as pointed out by others, you can use IO's Applicative instance in Control.Applicative and use the similar liftA2 function.

    You might notice that generic Applicatives have similar behavior to generic Monads in certain contexts, and the reason for this is because they're mathematically very similar. In fact, for every Monad, you can make an Applicative out of it. Consequently, you can also make a Functor out of every Applicative. There are a lot of people excited about the Functor-Applicative-Monad proposal that's been around for a while, and is finally going to be implemented in an upcoming version of GHC. They make a very natural hierarchy of Functor > Applicative > Monad.