How to pass a string list to putStr - haskell

How can a output a list of strings using putStr and map? I want to do something like:
s=["test1","test2"]
map putStr s
But have no experience with monads and don't know how to get it right...
Any kind of hint is enormously welcome!

The correct thing to do here is use mapM_ :: Monad m => (a -> m b) -> [a] -> m (). But if you'd like to learn a little about some useful Prelude functions...
We have two functions here,
map :: (a -> b) -> [a] -> [b]
putStr :: String -> IO ()
if we substitute the type of putStr into map (ie. a ~ String, b ~ IO ()) we get
map putStr :: [String] -> [IO ()]
so this takes a list of strings and gives us a list of IO () actions; IO computations that don't return anything usefull.
We'd like to turn that [IO ()] into something like IO (...) because we need IO to be the outermost layer in order to use it in main :: IO ()
The function sequence :: Monad m => [m a] -> m [a] from the Prelude is exactly what we need. It takes a list of monadic actions, executes them and returns the results in a list wrapped in the monad. Intuitively it moves the monad to the outermost layer.
sequence . map putStr :: [String] -> IO [()]
This is quite close, but we still have IO [()] instead of IO (), we don't really care about the [()] result and it'd be nice to ignore it. Again, the Prelude has what we need: sequence_ :: Monad m => [m a] -> m () which executes each monadic action in the list and ignores their return values.
Note that mapM_ is defined as
mapM_ f = sequence_ . map f

The type of map is:
map :: (a -> b) -> [a] -> [b]
this means that, since putStr returns an IO (), your expression will return a [IO ()].
You can, instead, use mapM_ (imported from Prelude) that will ignore the return type from the mapping and return an IO () which is a suitable return type for main:
main = do
let s=["test1","test2"]
mapM_ putStr s
Live demo

Related

How can I extract an IO () from Maybe and execute this?

I have this code:
trick = Just (putStrLn "Hello?")
And I want to unwrap this IO () out the Maybe context and call it.
main = do foo <- trick
foo
However, this throws an error:
Couldn't match type ‘IO’ with ‘Maybe’
Expected type: Maybe ()
Actual type: IO ()
How could I resolve this?
The function you are looking for is Data.Foldable.sequence_:
>>> Data.Foldable.sequence_ (Just (putStrLn "Hello?"))
Hello?
>>>
If your Maybe is Nothing, it will not do anything:
>>> Data.Foldable.sequence_ Nothing
>>>
This works because the type of Data.Foldable.sequence_ is:
Data.Foldable.sequence_
:: (Foldable t, Monad m) => t (m a) -> m ()
... and if you specialize t to Maybe and m to IO, you get:
Data.Foldable.sequence_ :: Maybe (IO a) -> IO ()
In the specific context of Maybe, it's equivalent to:
sequence_ (Just io) = do
_ <- io
return ()
sequence Nothing = return ()
The easiest solution to start out with is probably to realize that you can decide what to do based on the value of the Maybe (IO ()) via pattern matching.
maybeDoIO :: Maybe (IO ()) -> IO ()
maybeDoIO (Just io) = io
maybeDoIO Nothing = return ()
You have to take the Nothing into account, basically:
main = maybe (putStrLn "Nothing") id foo
The problem with your main function is that you are mixing two different monads in the same do block.
The foo <- trick action is "relative" to the Maybe monad but the foo action afterwards is an IO action. The type for >>= is:
Monad m => m a -> (a -> m b) -> m b
But in your case you'd need something with type:
Maybe a -> (a -> IO b) -> IO b
with two different monads.
If you want to execute the IO action then the type of main must be of the kind IO a so the do notation must refer to IO and not Maybe. Which means that you cannot use <- to extract the action but you have to use something else. For example Data.Maybe.fromMaybe:
import Data.Maybe
main = do fromMaybe (return ()) trick

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).

List of IO Strings

I'm new to Haskell and FP so this question may seem silly.
I have a line of code in my main function
let y = map readFile directoryContents
where directoryContents is of type [FilePath]. This in turn (I think) makes y type [IO String] , so a list of strings - each string containing the contents of each file in directoryContents.
I have a functions written in another module that work on [String] and String but I'm unclear as how to call/use them now because y is of type [IO String]. Any pointers?
EDIT:
It was suggested to me that I want to use mapM instead of map, so:
let y = mapM readFile directoryContents , and y is now type IO [String], what do I do from here?
You're correct, the type is y :: [IO String].
Well, there are essentially main two parts here:
How to turn [IO String] into IO [String]
[IO String] is a list of of IO actions and what we need is an IO action that carries a list of strings (that is, IO [String]). Luckily, the function sequence provides exactly what we need:
sequence :: Monad m => [m a] -> m [a]
y' = sequence y :: IO [String]
Now the mapM function can simplify this, and we can rewrite y' as:
y' = mapM readFile directoryContents
mapM does the sequence for us.
How to get at the [String]
Our type is now IO [String], so the question is now "How do we get the [String] out of the IO?" This is what the function >>= (bind) does:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
-- Specialized to IO, that type is:
(>>=) :: IO a -> (a -> IO b) -> IO b
We also have a function return :: Monad m => a -> m a which can put a value "into" IO.
So with these two functions, if we have some function f :: [String] -> SomeType, we can write:
ourResult = y' >>= (\theStringList -> return (f theStringList)) :: IO SomeType
Functions can be "chained" together with the >>= function. This can be a bit unreadable at times, so Haskell provides do notation to make things visually simpler:
ourResult = do
theStringList <- y'
return $ f theStringList
The compiler internally turns this into y' >>= (\theStringList -> f theStringList), which is the same as the y' >>= f that we had before.
Putting it all together
We probably don't actually want y' floating around, so we can eliminate that and arrive at:
ourResult = do
theStringList <- mapM readFile directoryContents
return $ f theStringList
Even more simplification
It turns out, this doesn't actually need the full power of >>=. In fact, all we need is fmap! This is because the function f only has one argument "inside" of IO and we aren't using any other previous IO result: we're making a result then immediately using it.
Using the law
fmap f xs == xs >>= return . f
we can rewrite the >>= code to use fmap like this:
ourResult = fmap f (mapM readFile directoryContents)
If we want to be even more terse, there is an infix synonym for fmap called <$>:
ourResult = f <$> mapM readFile directoryContents

Why is there a nested IO monad, IO (IO ()), as the return value of my function?

Why does this function have the type:
deleteAllMp4sExcluding :: [Char] -> IO (IO ())
instead of deleteAllMp4sExcluding :: [Char] -> IO ()
Also, how could I rewrite this so that it would have a simpler definition?
Here is the function definition:
import System.FilePath.Glob
import qualified Data.String.Utils as S
deleteAllMp4sExcluding videoFileName =
let dirGlob = globDir [compile "*"] "."
f = filter (\s -> S.endswith ".mp4" s && (/=) videoFileName s) . head . fst
lst = f <$> dirGlob
in mapM_ removeFile <$> lst
<$> when applied to IOs has type (a -> b) -> IO a -> IO b. So since mapM_ removeFile has type [FilePath] -> IO (), b in this case is IO (), so the result type becomes IO (IO ()).
To avoid nesting like this, you should not use <$> when the function you're trying to apply produces an IO value. Rather you should use >>= or, if you don't want to change the order of the operands, =<<.
Riffing on sepp2k's answer, this is an excellent example to show the difference between Functor and Monad.
The standard Haskell definition of Monad goes something like this (simplified):
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
However, this is not the only way the class could have been defined. An alternative runs like this:
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
Given that, you can define >>= in terms of fmap and join:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
ma >>= f = join (f <$> ma)
We'll look at this in a simplified sketch of the problem you're running into. What you're doing can be schematized like this:
ma :: IO a
f :: a -> IO b
f <$> ma :: IO (IO b)
Now you're stuck because you need an IO b, and the Functor class has no operation that will get you there from IO (IO b). The only way to get where you want is to dip into Monad, and the join operation is precisely what solves it:
join (f <$> ma) :: IO b
But by the join/<$> definition of >>=, this is the same as:
ma >>= f :: IO a
Note that the Control.Monad library comes with a version of join (written in terms of return and (>>=)); you could put that in your function to get the result you want. But the better thing to do is to recognize that what you're trying to do is fundamentally monadic, and thus that <$> is not the right tool for the job. You're feeding the result of one action to another; that intrinsically requires you to use Monad.

A better way to map a function that requires IO over a list

So lately I have a list of strings, and need to independently go over each one and perform some IO function.
So basically what I have is this:
goOverList :: [String] -> IO ()
goOverList (x:[]) = do
putStrLn x
goOverList (x:xs) = do
goOverList [x]
goOverList xs
main = do
let myList = ["first", "second", "third"]
goOverList myList
My IO is a bit more complicated but that is the gist of it (needing to have a function go over a list and do IO based on the list member) I was hoping someone might show me how to do this better.
Your goOverList function is almost equivalent to mapM_ putStrLn. (Just almost because mapM_ also works with the empty list while your function does not).
mapM is a function that applies a function of type a -> IO b¹ to each item in a list of as and gives you back an IO² with a list of bs. mapM_ is the same as mapM except that it doesn't store the results in a list (which doesn't make sense for actions that return () like putStrLn does).
¹ Actually it's more general than that: The function has type a -> m b where Monad m, but in this case m is IO.
² Again it's actually m.
sepp2k and solrize are right to recommend mapM_. But, in the spirit of teaching you to fish instead of giving you a fish, here's something you can try in the future:
Try to come up with the type signature of the operation that you need. For example, in your case, you want something of type (String -> IO ()) -> [String] -> IO ().
Go to the Hoogle search engine for Haskell libraries and search for that type.
That one has no results, so try modifying the type a bit to make it more generic. Replace String with a to get (a -> IO ()) -> [a] -> IO (), and search for that.
Now the third result of the second search is mapM_ :: Monad m => (a -> m b) -> [a] -> m (), which is exactly what you want. (The first answer, closeFdWith :: (Fd -> IO ()) -> Fd -> IO () is not a relevant result; the second, traverse_ :: (Foldable t, Applicative f) => (a -> f b) -> t a -> f () is relevant but a bit more complicated to understand and use.)
First, easy improvement:
goOverList' :: [String] -> IO ()
goOverList' [] = return ()
goOverList' (x:xs) = do
putStrLn x
goOverList' xs
The base case for recursion should be the empty list: in that case, you simply return the IO action return () which does nothing. When you have one or more elements, you print it and continue with the rest of the list, simple as that.
The same exact thing is achievable in a way more compact definition with mapM_ :: Monad m => (a -> m b) -> [a] -> m (): it is the same as the regular map, except that it works with monadic actions. Instead of returning the collection of results m [b] like the regular mapM would do, it throws it away. It works just fine for you in this case, as you're are only interested in printing out the elements of he list.
goOverList'' :: [String] -> IO ()
goOverList'' = mapM_ putStrLn
In order to be even more general, we could rely on print :: Show a => a -> IO () instead of putStrLn and accept in input every list of "showable" items:
goOverList''' :: (Show a) => [a] -> IO ()
goOverList''' = mapM_ print
data T = One | Two | Three deriving (Show)
main = do
let myList = [One, Two, Three]
goOverList''' myList
Your goOverList function can be written mapM_ putStrLn where mapM_ is a function in the standard Prelude.
You can also simplify your own implementation:
goOverList :: [String] -> IO ()
goOverList [] = return ()
goOverList (x:xs) = do
putStrLn x
goOverList xs

Resources