Carbon
Carbon

Reputation: 3943

Join two IOs with - in haskell

I need to join two IO Strings with a - in between. Here's what I came up with, which works - what's the right way?

import System.Environment
f :: String -> String -> IO String
f x y = (foldl1 (++)) <$> sequence [(getEnv x),(return "-"),(getEnv y)]

Upvotes: 4

Views: 227

Answers (3)

Daniel Wagner
Daniel Wagner

Reputation: 153162

I'll be honest, the idea behind your approach actually looks pretty sane to me. To start with, I'd probably use concat intsead of foldl1 (++), and drop some parens, getting us to:

f x y = concat <$> sequence [getEnv x, return "-", getEnv y]

This really doesn't seem that bad to me. But if I really wanted to push farther, here's some thoughts I would have. First, I'd recall the intercalate function.

f x y = intercalate "-" <$> sequence [getEnv x, getEnv y]

There's a handy shorthand for applying a function to each element of a list, too; mapM f = sequence . map f. So:

f x y = intercalate "-" <$> mapM getEnv [x,y]

I would stop there; it looks quite clean and maintainable to me.

Upvotes: 6

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477318

You could here use an applicative style function:

f :: String -> String -> IO String
f x y = withHyp <$> getEnv x <*> getEnv y
    where withHyp ex ey = ex ++ '-' : ey

So here we join the two Strings that are then joined with a hypen in the middle through the withHyp function.

Or for a list of environment variables that we need to fetch, we can use mapM and perform an intercalate:

import Data.List(intercalate)

f :: [String] -> IO String
f xs = intercalate "-" <$> mapM getEnv xs

Upvotes: 7

hnefatl
hnefatl

Reputation: 6037

One way of joining two IO Strings would be:

dash :: IO String -> IO String -> IO String
dash x y = do
    s1 <- x
    s2 <- y
    return $ s1 <> "-" <> s2

We "unbox" each of x and y to get the contained Strings, then "rebox` them with a hyphen (using the analogy for Functors).

It can be shortened to:

dash = liftA2 (\s1 s2 -> s1 <> "-" <> s2)

Where liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c takes a binary function and "lifts" it into a binary function on Applicatives, which are a superset of Monads.

Your f can then be implemented as f x y = dash (getEnv x) (getEnv y).

Upvotes: 4

Related Questions