Mapping over IO in Haskell - haskell

Is there a traditional way to map over a function that uses IO? Specifically, I'd like to map over a function that returns a random value of some kind. Using a normal map will result in an output of type ([IO b]), but to unpack the values in the list from IO, I need a something of type (IO [b]). So I wrote...
mapIO :: (a -> IO b) -> [a] -> [b] -> IO [b]
mapIO f [] acc = do return acc
mapIO f (x:xs) acc = do
new <- f x
mapIO f xs (new:acc)
... which works fine. But it seems like there ought to be a solution for this built into Haskell. For instance, an example use case:
getPercent :: Int -> IO Bool
getPercent x = do
y <- getStdRandom (randomR (1,100))
return $ y < x
mapIO (\f -> getPercent 50) [0..10] []

The standard way is via:
Control.Monad.mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
which is implemented in terms of sequence:
sequence :: (Monad m) => [m a] -> m [a]

Just to add to Don's answer, hake a look to the mapM_ function as well, which does exactly what mapM does but discards all the results so you get only side-effects.
This is useful if you want the have computations executed (for example IO computations) but are not interested in the result (for example, unlinking files).
And also see forM and forM_.

Related

Idiomatic way to handle nested IO in Haskell

I'm learning Haskell, and writing a short parsing script as an exercise. Most of my script consists of pure functions, but I have two, nested IO components:
Read a list of files from a path.
Read the contents of each file, which, in turn, will be the input for most of the rest of the program.
What I have works, but the nested IO and layers of fmap "feel" clunky, like I should either be avoiding nested IO (somehow), or more skillfully using do notation to avoid all the fmaps. I'm wondering if I'm over-complicating things, doing it wrong, etc. Here's some relevant code:
getPaths :: FilePath -> IO [String]
getPaths folder = do
allFiles <- listDirectory folder
let txtFiles = filter (isInfixOf ".txt") allFiles
paths = map ((folder ++ "/") ++) txtFiles
return paths
getConfig :: FilePath -> IO [String]
getConfig path = do
config <- readFile path
return $ lines config
main = do
paths = getPaths "./configs"
let flatConfigs = map getConfigs paths
blockConfigs = map (fmap chunk) flatConfigs
-- Parse and do stuff with config data.
return
I end up dealing with IO [IO String] from using listDirectory as input for readFile. Not unmanageable, but if I use do notation to unwrap the [IO String] to send to some parser function, I still end up either using nested fmap or pollute my supposedly pure functions with IO awareness (fmap, etc). The latter seems worse, so I'm doing the former. Example:
type Block = [String]
getTrunkBlocks :: [Block] -> [Block]
getTrunkBlocks = filter (liftM2 (&&) isInterface isMatchingInt)
where isMatchingInt line = isJust $ find predicate line
predicate = isInfixOf "switchport mode trunk"
main = do
paths <- getPaths "./configs"
let flatConfigs = map getConfig paths
blockConfigs = map (fmap chunk) flatConfigs
trunks = fmap (fmap getTrunkBlocks) blockConfigs
return $ "Trunk count: " ++ show (length trunks)
fmap, fmap, fmap... I feel like I've inadvertently made this more complicated than necessary, and can't imagine how convoluted this could get if I had deeper IO nesting.
Suggestions?
Thanks in advance.
I think you want something like this for your main:
main = do
paths <- getPaths "./configs"
flatConfigs <- traverse getConfig paths
let blockConfigs = fmap chunk flatConfigs
-- Parse and do stuff with config data.
return ()
Compare
fmap :: Functor f => (a -> b) -> f a -> f b
and
traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
They are quite similar, but traverse lets you use effects like IO.
Here are the types again specialized a little for comparison:
fmap :: (a -> b) -> [a] -> [b]
traverse :: (a -> IO b) -> [a] -> IO [b]
(traverse is also known as mapM)
Your idea of 'nestedness' is actually a pretty good insight into what monads are. Monads can be seen as Functors with two additional operations, return with type a -> m a and join with type m (m a) -> m a. We can then make functions of type a -> m b composable:
fmap :: (a -> m b) -> m a -> m (m b)
f =<< v = join (fmap f v) :: (a -> m b) -> m a -> m b
So we want to use join here but have m [m a] at the moment so our monad combinators won't help directly. Lets search for m [m a] -> m (m [a]) using hoogle and our first result looks promising. It is sequence:: [m a] -> m [a].
If we look at the related function we also find traverse :: (a -> IO b) -> [a] -> IO [b] which is similarly sequence (fmap f v).
Armed with that knowledge we can just write:
readConfigFiles path = traverse getConfig =<< getPaths path

How do I use map over a list with do notation - ie avoid type `IO ()' with type `[IO ()]'?

So this question is about Monads more generally (in particuar for Fay), but my example uses the IO monad.
I have a function where the input is a list of strings and I would like to print each string one by one. So here was my idea:
funct :: [String] -> ?
funct strs = do
map putStrLn strs
But doesn't work because it returns a type [IO ()]. So my question is, how would I map over a list, and treat it as if I'm performing the function line by line, in typical do-notation, iterative style (like below)?
funct :: [String] -> IO ()
funct strs = do
putStrLn (strs !! 0)
putStrLn (strs !! 1)
...
Most of the standard library list functions have monadic versions that end with M:
map :: (a -> b) -> [a] -> [b]
mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
replicate :: Int -> a -> [a]
replicateM :: (Monad m) => Int -> m a -> m [a]
etc. Sometimes they are in Prelude, sometimes they are in the Control.Monad. I recommend using hoogle to find them.
Specifically for your case, i use mapM_ putStrLn quite often.
Use sequence
sequence $ map putStrLn strings
sequence pulls the monad out of a list of monads
sequence :: Monad m => [m a] -> m [a]
thus converting (map putStrLn strings)::[IO a] to IO [a]. You might want to use the related sequence_ to drop the return value also.
You can also use forM_:: Monad m => [a] -> (a -> m b) -> m () (which often looks nicer, but has a bit of an imperative feel to me).

Haskell: Filtering through a dictionary/hash/map with IO() values

I have a function which signature is String -> String -> IO (Maybe String)
Now, I use this function to build values for a dictionary and I end up with: [(String,IO (Maybe String))]
I have to analyze the values in the dictionary and based on the result return the appropriate key. I was hoping to just use filter on the Map to step through it but I can't think of a way to extract that IO action on the fly. So how do I map/filter through the dictionary running the IO action and based on the result of the IO action's value return appropriate key of the dictionary?? Is there an easy way of doing it or I just got myself in a mess?
Thanks.
Perhaps the solution is to use sequence with something like
sequence . map (\(a,mb) -> (mb >>= \b -> return (a,b)))
then you can simply use liftM to apply your filter to the resulting IO [(String,Maybe String)].
liftM is in Control.Monad. Alternatively, in do notation
myFilter :: (String,(Maybe String)) -> Bool)
-> [(String,IO (Maybe String))]
-> IO [(String,(Maybe String))]
myFilter f ml =
do
l <- sequence . map (\(a,mb) -> (mb >>= \b -> return (a,b))) $ ml
return $ filter f ml
Perhaps some refactoring is in order. Often when working with monads you want to use mapM instead of map.
There is also a filterM function in Control.Monad. It might be what you need.
Edit: it was pointed out in comments that
sequence . map (\(a,mb) -> (mb >>= \b -> return (a,b))) $ ml
is equivalent to
mapM (\(a,mb) -> fmap ((,) a) mb) ml
so
myFiter' f = (liftM $ filter f) . mapM (\(a,mb) -> fmap ((,) a) mb)
I have a function which signature is String -> String -> IO (Maybe String) Now, I use this function to build values for a dictionary and I end up with: [(String,IO (Maybe String))]
This part doesn't add up for me. How do you input only 2 strings, and end up with a meaningful result of type [(String, IO (Maybe String))]?
Lacking the particulars, lets assume your situation is something like this:
f :: String -> String -> IO (Maybe String)
magic :: String -> (String, String)
magic takes some key, and somehow splits the key into the two input strings needed by f. So, assuming you have a list of keys, you would wind up with a [(String, IO (Maybe String))] like this:
-- ks :: [String]
myMap = map (\k -> let (a,b) = magic k in (k, f a b)) ks
But...wouldn't it be so much nicer if we had a [(String, Maybe String)] instead? Assuming we're inside an IO action...
someIOAction = do
...
myMap <- monadicMagicks (\k -> let (a,b) = magic k in (k, f a b)) ks
But what monadicMagicks could we use to make this work out right? Let's look at the types that we expect from these expressions
monadicMagicks (\k -> ...) ks :: IO [(String, Maybe String)]
(\k -> let (a,b) = magic k in (k, f a b)) :: String -> (String, IO (Maybe String))
ks :: [String]
-- therefore
monadicMagicks :: (String -> (String, IO (Maybe String)))
-> [String]
-> IO [(String, Maybe String)]
Stop...Hoogle time. Let's generalize what we're looking for a bit, first. We have two basic data types here: String, which appears to be the "input", and Maybe String, which appears to be the "output". So let's replace String with a and Maybe String with b. So we're looking for (a -> (a, IO b)) -> [a] -> IO [(a, b)]. Hrm. No results found. Well, if we could get a result type of just IO [b], then in a do block we could get it out of IO, and then zip it with the original key list. That also means the function we put in wouldn't have to perform the pairing of key with result. So let's simplify what we're looking for and try again: (a -> IO b) -> [a] -> IO [b]. Hey, check it out! mapM matches that type signature perfectly.
monadicMagicks :: (a -> IO b) -> [a] -> IO [(a, b)]
monadicMagicks f xs = do
ys <- mapM f xs
return $ zip xs ys
This could actually be written more succinctly, and with a more general type signature:
monadicMagicks :: Monad m => (a -> m b) -> [a] -> m [(a, b)]
monadicMagicks f xs = zip xs `liftM` mapM f xs
someIOAction = do
...
-- Like we said, the lambda no longer has to pair up the key with the result
myMap <- monadicMagicks (\k -> let (a,b) = magic k in f a b) ks
This last line could also be rewritten a bit shorter, if you're comfortable with function composition:
myMap <- monadicMagicks (uncurry f . magic) ks
Note that monadicMagicks might not make much sense for some monads, which is probably why it isn't in the standard libs. (For example, using mapM in the list monad usually means that the result will have a different length than the input):
ghci> mapM (\x -> [x, -x]) [1,2]
[[1,2],[1,-2],[-1,2],[-1,-2]]

Using map with two lists rather than one. Can you nest?

I need to run a function that takes two arguments several times. I have two lists containing these arguments and I'd like to be able to use map or something similar to call the function with the corresponding args.
The function I want to call has this type:
runParseTest :: String -> String -> IO()
The lists are created like this:
-- Get list of files in libraries directory
files <- getDirectoryContents "tests/libraries"
-- Filter out ".." and "." and add path
let names = filter (\x -> head x /= '.') files
let libs = ["tests/libraries/" ++ f | f <- names]
So lets say that names contains ["test1.js", "test2.js", "test3.js"] and libs contains ["tests/libraries/test1.js", "tests/libraries/test2.js", "tests/libraries/test3.js"]
I want to call them like this:
runParseTest "test1.js" "tests/libraries/test1.js"
runParseTest "test2.js" "tests/libraries/test2.js"
runParseTest "test3.js" "tests/libraries/test3.js"
I know I could create a helper function that does this fairly easily, but out of interest, is it possible to do in one line using map?
This is what I have so far, but obviously the first argument is always "test":
mapM_ (runParseTest "test") libs
I apologise if this is unclear. I can provide more info if necessary.
This is a great time to use Hoogle! Hoogle is a search engine for searching Haskell types. For instance, a Hoogle query for (a -> b) -> [a] -> [b] pulls up map. Here, you have a function of type String -> String -> IO (); you want a function of type (String -> String -> IO ()) -> [String] -> [String] -> IO (). Hoogle can often generalize by itself, but it's having trouble here, so let's help it out: You just want (a -> a -> IO ()) -> [a] -> [a] -> IO () for any a. If you Hoogle for that type signature, the first result is zipWithM_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m () in the Control.Monad module, which does exactly what you want. This is part of a family of functions, with varying degrees of generality:
zip :: [a] -> [b] -> [(a,b)], which pairs up two lists, truncating the shorter one.
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c], which runs a supplied function on elements from each of the two lists; zip = zipWith (,).
zipWithM :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c], which is like zipWith inside a monad; zipWithM f xs ys = sequence $ zipWith f xs ys.
zipWithM_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m (), which is like zipWithM but discards its result; zipWithM_ f xs ys = zipWithM f xs ys >> return () = sequence_ $ zipWith f xs ys.
zip3 :: [a] -> [b] -> [c] -> [(a, b, c)], whose functionality I'm sure you can figure out :-)
zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d], which is like zipWith on three lists; zipWith3 = zip (,,).
A family of zipN and zipWithN functions in Data.List, going up through zip7/zipWith7. (Arguably, this starts with id :: [a] -> [a] as zip1 and map :: (a -> b) -> [a] -> [b] as zipWith1, which is where your question comes from.)
And, in greatest generality, the ZipList applicative functor. Given some lists xs1…xsN, then runZipList $ f <$> ZipList xs1 <*> ZipList xs2 <*> ... <*> ZipList xsN = runZipList $ liftAN f (ZipList xs1) ... (ZipList xsN) behaves just like zipWithN f xs1 ... xsN.
So, in your specific use case, we're going to have—with a few extra changes—the following:
import Data.List (isPrefixOf)
...
-- I got rid of `head` because it's a partial function, and I prefer `map` to
-- list comprehensions for simple things
do files <- getDirectoryContents "tests/libraries"
let names = filter (not . ("." `isPrefixOf`)) files
libs = map ("tests/libraries/" ++) names
zipWithM_ runParseTest names libs
So lets say that names contains ["test1.js", "test2.js", "test3.js"]
and libs contains ["tests/libraries/test1.js", "tests/libraries/test2.js", "tests/libraries/test3.js"]
I want to call them like this:
runParseTest "test1.js" "tests/libraries/test1.js"
runParseTest "test2.js" "tests/libraries/test2.js"
runParseTest "test3.js" "tests/libraries/test3.js"
It's possible to do that with zip:
map (\(a,b) -> runParseTest a b) $ zip names libs
Or maybe uncurry runParseTest:
map (uncurry runParseTest) $ zip names libs
Or with zipWith:
zipWith runParseTest names libs
And like Ozgur said, there are some analogues for monads:
> :t zipWithM
zipWithM :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]
> :t zipWithM_
zipWithM_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()
You are looking for zipWithM_.
You say you could write a helper function which does this. Which means you know the type of the function you are looking for. In such cases you can use hoogle.
(Try: Monad m => [a] -> [b] -> m ())
While waiting for answers I created a solution of my own with a new function called map2M_ based on the source code for map and mapM_:
map2 :: (a -> b -> c) -> [a] -> [b] -> [c]
map2 _ [] _ = []
map2 _ _ [] = []
map2 f (a:as) (b:bs) = f a b : map2 f as bs
map2M_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()
map2M_ f as bs = sequence_ (map2 f as bs)

Haskell IO Bool fold question

How can I write a function that does logical and function between the elements of the list?
I have written this:
iand :: [IO Bool] -> IO Bool
iand [] = return (True)
iand (x:xs) = do
a <- x
b <- iand(xs)
return (a && b)
But that seems to be unconscice.
How can this function be rewritten with foldM (liftM)?
Thank you.
The Prelude function and :: [Bool] -> Bool almost does what you want, but it's not monadic. Generally speaking, to lift a one-argument function into a monad, you'll want Control.Monad's liftM :: Monad m => (a -> b) -> m a -> b a; however, to be more general, you can use the Prelude's fmap :: Functor f => (a -> b) -> f a -> f b. All monads are functors1, so this is ok. Thus, you can use
fand' :: Functor f => f [Bool] -> f Bool
fand' = fmap and
However, at least 90% of the time, I would just write that inline as fmap and xs, or more probably and <$> xs, using Control.Applicative's <$> synonym for fmap.
Of course, as I'm sure you noticed, this isn't what you want. For that, you need the Prelude's sequence :: Monad m => [m a] -> m [a]. You now have a function [m a] -> m [a], and a function f [Bool] -> f Bool, so we can combine these:
mand :: Monad m => [m Bool] -> m Bool
mand = liftM and . sequence
I switched to liftM from fmap because, although fmap's "nicer" in some sense, it would impose an additional Functor m constraint. That shouldn't be a problem, but it could be for historical reasons, so I played it safe.
Also, you might ask "How would I have ever known about sequence"? The answer to that is the wonderful Hoogle, which allows you to search for Haskell functions by name or type. So, since you knew about liftM :: Monad m => (a -> b) -> m a -> m b, you might have realized you needed something like Monad m => [m a] -> m [a]; Hoogling for that does indeed turn up sequence.
1: Or, at least, they should be—for historical reasons, though, this isn't always the case.
You can use liftM to turn and (which has type [Bool] -> Bool) into a function of type IO [Bool] -> IO Bool and sequence to turn your [IO Bool] into an IO [Bool].
So your function becomes:
iand ibs = liftM and (sequence ibs)
Wouldn't this be iand list = foldl (&&) True list ?

Resources