I'm new to haskell and functional programming in general and I have a problem with monads. Let's say I have got a list of filenames:
-- do block --
let filenames = ["file1","file2"]
and I want to generate a list of those files' content, using list comprehensions:
let content = [str <- readFile f | f <- filenames]
Ofc, this kind of usage is not valid.
As I understand this kind of "assignment" can be used in do block, when "chaining" the result with the next instruction.
Is there maybe an alternative way to use the left arrow (or >>=) operator. I imagine sth like this:
let content = [leftArrAlter $ readFile f | f <- filenames]
Let's start with the simpler list
let content = [readFile f | f <- filenames]
content has type [IO String]; it's a list of IO actions, each of which can produce a String when executed.
What you would like is something of type IO [String]: a single IO action that, when executed, gives you a list of String values.
That's where the sequence function comes in. In this case, we only need to consider the specialized version that has type [IO String] -> IO [String]:
content <- sequence [readFile f | f <- filenames]
We can also use traverse, in particular the specialized version with type (FilePath -> IO String) -> [FilePath] -> IO [String]:
content <- traverse readFile fileNames
For reference, the general types of the two functions:
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
We used [] as our Traversable, and IO as our Monad/Applicative.
Related
The lines function in Haskell separates the lines of a string into a string list:
lines :: String -> [String]
The readFile function reads a file into a string:
readFile :: FilePath -> IO String
Trying to compose these functions to get a list of lines in a file results in a type error:
Prelude> (lines . readFile) "quux.txt"
<interactive>:26:10: error:
• Couldn't match type ‘IO String’ with ‘[Char]’
Expected type: FilePath -> String
Actual type: FilePath -> IO String
• In the second argument of ‘(.)’, namely ‘readFile’
In the expression: lines . readFile
In the expression: (lines . readFile) "quux.txt"
How can I do the monad trick here?
You can't compose them, at least not with (.) alone. You can use fmap (or its operator version <$>), though:
lines <$> readFile "quux.txt" -- Produces IO [String], not [String]
One way to express this in terms of a kind of composition is to first create a Kleisli arrow (a function of type a -> m b for some monad m) from lines:
-- return . lines itself has type Monad m => String -> m [String]
-- but for our use case we can restrict the type to the monad
-- we are actually interested in.
kleisliLines :: String -> IO [String]
kleisliLines = return . lines
Now you can use the Kleisli composition operator >=> to combine readFile (itself a Kleisli arrow) and lines:
import Control.Monad -- where (>=>) is defined
-- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
-- Here, m ~ IO
-- a -> FilePath
-- b -> String
-- c -> [String]
(readFile >=> kleisliLines) "quux.txt"
Compare this with the >>= operator, which requires you to supply the file name to readFile before feeding the result to return . lines:
-- m >>= return . f === fmap f m === f <$> m
readFile "quux.txt" >>= kleisliLines
>=> is natural if you are already thinking of a pipeline in terms of >=; if you want something that preserves the order of ., use <=< (also defined in Control.Monad, as (<=<) = flip (>=>); the operands are simply reversed).
(kleisliLines <=< readFile) "quux.txt"
The other answers given so far have been to make lines produce an empty monadic context, and then use monadic composition (<=<) to compose it with readFile. But you can also go the other direction: lift lines to operate through a monadic argument, and then use ordinary composition to combine it with readFile:
(fmap lines . readFile) "quux.txt"
Of course, if you're going to immediately apply this to an argument, it's simpler to just write
lines <$> readFile "quux.txt"
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
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
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 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.
import Control.Applicative (liftA2)
(+++) :: Applicative f => f [a] -> f [a] -> f [a]
(+++) = liftA2 (++)
Now in GHCI
>> getLine +++ getLine
Hello <ENTER>
World!<ENTER>
Hello World!
(++) <$> pure "stringOne" <*> pure "stringTwo"
implement function (+++) ... which works exactly as (++) :: [a] -> [a] -> [a] but for IO String?
Don't do that, it's a bad idea. Concatenating strings is a purely functional operation, there's no reason to have it in the IO monad. Except at the place where you need the result – which would be somewhere in the middle of some other IO I suppose. Well, then just use do-notation to bind the read strings to variable names, and use ordinary (++) on them!
do
print "Now start obtaining strings..."
somePreliminaryActions
someMoreIOStuff
s1 <- getS1
s2 <- getS2
yetMoreIO
useConcat'dStrings (s1 ++ s2)
print "Done."
It's ok to make that more compact by writing s12 <- liftA2 (++) getS1 getS2. But I'd do that right in place, not define it seperately.
For longer operations you may of course want to define a seperate named action, but it should be a somehow meaningful one.
You shouldn't think of IO String objects as "IO-strings". They aren't, just as [Int] aren't "list-integers". An object of type IO String is an action which, when incurred, can supply a String object in the IO monad. It is not a string itself.
Give a definition of the function
fmap :: (a->b) -> IO a -> IO b
the effect of which is to transform an interaction by applying the function to its result. you should define it using the do construct.
how should I define the fmap? I have no idea about it?
could someone help me with that?
Thanks~!
It looks like homework or something so I will give you enough hint so that you can work rest of the details yourself.
fmap1 :: (a -> b) -> IO a -> IO b
fmap1 f action =
action is as IO action and f is a function from a to b and hence type a -> b.
If you are familiar with monadic bind >>= which has type (simplified for IO monad)
(>>=) :: IO a -> (a -> IO b) -> IO b
Now if you look at
action >>= f
It means perform the IO action which returns an output (say out of type a) and pass the output to f which is of type a -> IO b and hence f out is of type IO b.
If you look at the second function called return which has type (again simlified for IO monad)
return :: a -> IO a
It takes a pure value of type a and gives an IO action of type IO a.
Now lets look back to fmap.
fmap1 f action
which performs the IO action and then runs f on the output of the action and then converts the output to another IO action of type IO b. Therefore
fmap1 f action = action >>= g
where
g out = return (f out)
Now comes the syntactic sugar of do notation. Which is just to write bind >>= in another way.
In do notation you can get the output of an action by
out <- action
So bind just reduces to
action >>= f = do
out <- action
f out
I think now you will be able to convert the definition of fmap to do construct.
Are you familiar with map?
The type of map is
map :: (a -> b) - > [a] -> [b]
if you run
map (*5) [1,2,3]
you get
[5,10,15]
The point of map is to give it a transform function and a source list and have it apply the transform to the list to get a result list.
map is fmap for lists. They want you to write an fmap for IO types, does this help?
if You want to know more about fmap read http://learnyouahaskell.com/making-our-own-types-and-typeclasses#the-functor-typeclass
Note that every monad is a already a functor. If you want to reimplement fmap, however, you can do that in terms of monadic functions easily. One monad law is this:
fmap f xs = xs >>= return . f
If you understand do notation enough, you should be able to translate that yourself. If not, just ask.