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?
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 Applicative
s have similar behavior to generic Monad
s 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
.
import Control.Applicative (liftA2)
(+++) :: Applicative f => f [a] -> f [a] -> f [a]
(+++) = liftA2 (++)
Now in GHCI
>> getLine +++ getLine
Hello <ENTER>
World!<ENTER>
Hello World!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With