List of IO Strings - haskell

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

Related

Haskell handling getting Int from user input [duplicate]

How can I use pure functions inside IO functions? :-/
For example: I'm reading a file (IO function) and I want to parse its context, a string, by using a pure function with referential transparency.
It seems such worlds, pure functions and IO functions, are separated. How can I possibly bridge them?
The simplest way is to use fmap, which has the following type:
fmap :: (Functor f) => (a -> b) -> f a -> f b
IO implements Functor, which means that we can specialize the above type by substituting IO for f to get:
fmap :: (a -> b) -> IO a -> IO b
In other words, we take some function that converts as to bs, and use that to change the result of an IO action. For example:
getLine :: IO String
>>> getLine
Test<Enter>
Test
>>> fmap (map toUpper) getLine
Test<Enter>
TEST
What just happened there? Well, map toUpper has type:
map toUpper :: String -> String
It takes a String as an argument, and returns a String as a result. Specifically, it uppercases the entire string.
Now, let's look at the type of fmap (map toUpper):
fmap (map toUpper) :: IO String -> IO String
We've upgraded our function to work on IO values. It transforms the result of an IO action to return an upper-cased string.
We can also implement this using do notation, to:
getUpperCase :: IO String
getUpperCase = do
str <- getLine
return (map toUpper str)
>>> getUpperCase
Test<Enter>
TEST
It turns out that every monad has the following property:
fmap f m = do
x <- m
return (f x)
In other words, if any type implements Monad, then it should always be able to implement Functor, too, using the above definition. In fact, we can always use the liftM as the default implementation of fmap:
liftM :: (Monad m) => (a -> b) -> m a -> m b
liftM f m = do
x <- m
return (f x)
liftM is identical to fmap, except specialized to monads, which are not as general as functors.
So if you want to transform the result of an IO action, you can either use:
fmap,
liftM, or
do notation
It's really up to you which one you prefer. I personally recommend fmap.
You can also consider liftM function from Control.Monad.
A little example to help you (run it into ghci as you are under the IO Monad)
$ import Control.Monad -- to emerge liftM
$ import Data.Char -- to emerge toUpper
$ :t map to Upper -- A pure function
map toUpper :: [Char] -> [Char]
$ :t liftM
liftM :: Monad m => (a1 -> r) -> m a1 -> m r
$ liftM (map toUpper) getLine
The actual answer is as follows:
main = do
val <- return (purefunc ...arguments...)
...more..actions...
return wraps it in the appropriate monad so that do can assign it to val.
Alex Horsman helped me. He said:
"Perhaps I'm misunderstanding, but that sounds pretty simple?
do {x <- ioFunc; return (pureFunc x)}"
And then I solved my problem:
import System.IO
import Data.List
getFirstPart line Nothing = line
getFirstPart line (Just index) = fst $ splitAt index line
eliminateComment line =
getFirstPart line $ elemIndex ';' line
eliminateCarriageReturn line =
getFirstPart line $ elemIndex '\r' line
eliminateEntersAndComments :: String -> String
eliminateEntersAndComments text =
concat $ map mapFunction $ lines text
where
mapFunction = (++ " ") . eliminateCarriageReturn . eliminateComment
main = do {
contents <- readFile "../DWR-operators.txt";
return (eliminateEntersAndComments contents)
}

Haskell - How to combine two monadic Maybe functions into a single function

Let's say I have these two data records, X and Y and following two functions:
f1 :: IO (Maybe [X])
f2 :: X -> IO (Maybe Y)
I need to call the f1 first and then, for each element of returned list (stored in IO (Maybe)) call the f2, which would result in something like IO (Maybe [IO (Maybe Y)]). How can I compose them to get something meaningful, such as
result :: Maybe (IO [Y])
or
result :: IO (Maybe [Y])
?
Thanks a lot for any help :-)
Essentially it's using fmap sequenceA . sequenceA . fmap f2.
Using do syntax and breaking it down one step at a time:
result and result' gives you the same result.
data X = X
data Y = Y
f1 :: IO (Maybe [X])
f1 = undefined
f2 :: X -> IO (Maybe Y)
f2 = undefined
result :: IO (Maybe [Y])
result = do
f1' <- f1
case f1' of
Just f1'' -> do
let a = fmap f2 f1'' :: [IO (Maybe Y)]
let b = sequenceA a :: IO [Maybe Y]
fmap sequenceA b :: IO (Maybe [Y])
Nothing -> pure Nothing
result' :: IO (Maybe [Y])
result' = do
f1' <- f1
case f1' of
Just f1'' -> do
fmap sequenceA . sequenceA . fmap f2 $ f1''
Nothing -> pure Nothing
A candidate could be:
result :: IO (Maybe [Y])
result = f1 >>= fmap sequenceA . mapM f2 . concat
Here concat is a function concat :: Foldable f => f [a] -> [a] that will convert a Nothing to an empty list, and a Just xs to xs.
We can then make a mapM f2 to generate an IO [Maybe a], and fmap :: Functor f => (a -> b) -> f a -> f b with sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a) to convert an IO [Maybe Y] to an IO (Maybe [Y]).
sequenceA will return a Nothing if the list contains one or more Nothings, and return a Just xs if the list contains only Justs with xs the values that originally have been wrapped in Justs.
note: this answer is not very suitable for Haskell newcomers because it involves a monad transformer.
Once we start mixing IO with the processing and generation of lists, I tend to jump straight away to the Stream monad transformer from streaming, that allows you to cleanly interleave the execution of IO actions with the "yielding" of values to be consumed downstream. In a way, Stream is an "effectful list" that performs effects every time we "extract" a value from it.
Consider this version of f1:
import Streaming
import qualified Streaming.Prelude as S
import Data.Foldable (fold)
f1' :: Stream (Of X) IO ()
f1' = do
mxs <- lift f1
S.each (fold mxs)
lift promotes an IO a action to a Stream (Of x) a that doesn’t yield anything, but returns a as the "final value" of the Stream. (Streams yield zero or more values when consumed, and return a final value of a different type once they are exhausted).
Streaming.Prelude.each takes anything that can be converted to a list and returns a Stream that yields the element of the list. Basically, it promotes pure lists to effectful lists.
And Data.Foldable.fold is working here with the type fold :: Maybe [a] -> [a] to get rid of that Maybe.
Here's the corresponding version of f2:
f2' :: X -> Stream (Of Y) IO ()
f2' x = do
ys <- lift (f2 x)
S.each ys
Combining them is quite simple, thanks to Streaming.Prelude.for.
result' :: Stream (Of Y) IO ()
result' = S.for f1' f2'
With functions like Streaming.Prelude.take, we could read one Y from the result without having to perform the effects required by the next Y. (We do need to read all the Xs in one go though, because the f1 we are given already does that).
If we want to get all the Ys, we can do it with Streaming.Prelude.toList_:
result :: IO [Y]
result = S.toList_ result'

How does `return` statement have different type than that of a function's definition?

Within a loop, integers are collected inside a list, and a tuple of these integers is returned. How does this change to a list of tuples?
input :: IO [(Int,Int)]
input = do
n <- readLn :: IO Int
forM [1..n] $ \_ -> do
[x,y] <- map read . words <$> getLine
return (x,y)
I expected type of value to be (Int,Int) but it is [(Int,Int)]. Why?
Let's re-write your code with explicit separators making the code structure more self-apparent:
input :: IO [(Int,Int)]
input = do {
n <- readLn ;
forM [1..n] (\ _ -> do {
[x,y] <- fmap (map read . words) getLine ;
return (x,y) })
}
so return (x,y) belongs to the internal do.
Since there's a getLine :: IO String there, the internal do's type is IO (t1,t2) where x :: t1, y :: t2. So this is also the return type of that lambda function participating in that forM call.
Since forM :: Monad m => [a] -> (a -> m b) -> m [b], and we know m ~ IO here, we get the type of the overall do's last expression as
forM :: [a] -> (a -> IO b) -> IO [b]
and thus the overall type is IO [b] ~ IO [(t1,t2)] since b ~ (t1,t2) as per that return expression.
The lambda function returns IO b so forM returns IO [b] as per its type above. And the type of do block is the same as the type of its last expression.
The function's signature says it's IO [(Int,Int)], so finally t1 ~ Int and t2 ~ Int and everything fits.

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

Haskell - How can I use pure functions inside IO functions?

How can I use pure functions inside IO functions? :-/
For example: I'm reading a file (IO function) and I want to parse its context, a string, by using a pure function with referential transparency.
It seems such worlds, pure functions and IO functions, are separated. How can I possibly bridge them?
The simplest way is to use fmap, which has the following type:
fmap :: (Functor f) => (a -> b) -> f a -> f b
IO implements Functor, which means that we can specialize the above type by substituting IO for f to get:
fmap :: (a -> b) -> IO a -> IO b
In other words, we take some function that converts as to bs, and use that to change the result of an IO action. For example:
getLine :: IO String
>>> getLine
Test<Enter>
Test
>>> fmap (map toUpper) getLine
Test<Enter>
TEST
What just happened there? Well, map toUpper has type:
map toUpper :: String -> String
It takes a String as an argument, and returns a String as a result. Specifically, it uppercases the entire string.
Now, let's look at the type of fmap (map toUpper):
fmap (map toUpper) :: IO String -> IO String
We've upgraded our function to work on IO values. It transforms the result of an IO action to return an upper-cased string.
We can also implement this using do notation, to:
getUpperCase :: IO String
getUpperCase = do
str <- getLine
return (map toUpper str)
>>> getUpperCase
Test<Enter>
TEST
It turns out that every monad has the following property:
fmap f m = do
x <- m
return (f x)
In other words, if any type implements Monad, then it should always be able to implement Functor, too, using the above definition. In fact, we can always use the liftM as the default implementation of fmap:
liftM :: (Monad m) => (a -> b) -> m a -> m b
liftM f m = do
x <- m
return (f x)
liftM is identical to fmap, except specialized to monads, which are not as general as functors.
So if you want to transform the result of an IO action, you can either use:
fmap,
liftM, or
do notation
It's really up to you which one you prefer. I personally recommend fmap.
You can also consider liftM function from Control.Monad.
A little example to help you (run it into ghci as you are under the IO Monad)
$ import Control.Monad -- to emerge liftM
$ import Data.Char -- to emerge toUpper
$ :t map to Upper -- A pure function
map toUpper :: [Char] -> [Char]
$ :t liftM
liftM :: Monad m => (a1 -> r) -> m a1 -> m r
$ liftM (map toUpper) getLine
The actual answer is as follows:
main = do
val <- return (purefunc ...arguments...)
...more..actions...
return wraps it in the appropriate monad so that do can assign it to val.
Alex Horsman helped me. He said:
"Perhaps I'm misunderstanding, but that sounds pretty simple?
do {x <- ioFunc; return (pureFunc x)}"
And then I solved my problem:
import System.IO
import Data.List
getFirstPart line Nothing = line
getFirstPart line (Just index) = fst $ splitAt index line
eliminateComment line =
getFirstPart line $ elemIndex ';' line
eliminateCarriageReturn line =
getFirstPart line $ elemIndex '\r' line
eliminateEntersAndComments :: String -> String
eliminateEntersAndComments text =
concat $ map mapFunction $ lines text
where
mapFunction = (++ " ") . eliminateCarriageReturn . eliminateComment
main = do {
contents <- readFile "../DWR-operators.txt";
return (eliminateEntersAndComments contents)
}

Resources