Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 907
d12frosted Avatar asked Nov 27 '22 05:11

d12frosted


2 Answers

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.

like image 72
bheklilr Avatar answered Dec 05 '22 03:12

bheklilr


import Control.Applicative (liftA2)

(+++) :: Applicative f => f [a] -> f [a] -> f [a]
(+++) = liftA2 (++)

Now in GHCI

>> getLine +++ getLine
Hello <ENTER>
World!<ENTER>
Hello World!
like image 36
Chris Taylor Avatar answered Dec 05 '22 02:12

Chris Taylor