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

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'

Related

Extracting `a` from Applicative `f a`

Learn You a Haskell offers the following exercise:
Let's try implementing a function that takes a list of applicatives and
returns an applicative that has a list as its result value.
LYAH gives the type signature sequenceA' :: (Applicative f) => [f a] -> f [a]
I started with Applicative, but wasn't sure how to extract a from f a in a general way for all Applicative's.
So, I implemented it as a Maybe. Of course this is unacceptable for all `Applicative's.
import Control.Applicative
sequenceA' :: (Num a) => [Maybe a] -> Maybe [a]
sequenceA' [] = pure []
sequenceA' xs = pure $ [extract' x | x <- xs ]
extract' :: (Num a) => Maybe a -> a
extract' x = case x of
Just y -> y
Nothing -> 0
How can I extract a from f a where f is an Applicative?
You can't in general. In fact, the Maybe example you gave is a good example of why since it requires it to be a Num instance. It wouldn't make sense for the Maybe Applicative in general, so that would be a counterexample to a general solution. Another counterexample would be IO. There is no valid extract implementation for IO.
To make a function that is general enough to work with all Applicative instances, you must be able to construct the function using only methods from Applicative and its super-class, Functor. There is no way to make extract using only fmap, pure and (<*>).
It's not necessary to take things out of the applicative functor to achieve this.
The great thing about applicative functors is they allow you to use ordinary functions on the results of each applicative computation, so
if you have applicatives c1, c2 and c3 of types f a, f b, f c
that produce values v1, v2 and v3 of types a, b and c,
but you actually want to use a function g :: a -> b -> c -> d on the values
to produce g v1 v2 v3 :: d, then you can do
g <$> c1 <*> c2 <*> c3
which has type f d.
So we can use the function (:) to join the first value out of our list of applicatives with the rest of them, so you can do someytthing like (:) <$> thingThatGivesFirstValue <*> thing that gives the rest of the list. So it'll be a nice recursion if you pattern match on the list of applicatives.
sequenceA' :: (Applicative f) => [f a] -> f [a]
sequenceA' [] = -- just give the empty list
sequenceA' (c:cs) = -- hmm. What could go here then?
so for example you should get
ghci> sequenceA' [getLine, getLine, getLine]
Hello
there
everyone
["Hello","there","everyone"]
ghci> sequenceA' [Just 3, Just 4, Just 5]
Just [3,4,5]
Here's an example function to help you along with the recursice case:
nth :: Applicative f => f Int -> f [a] -> f a
nth wrappedInt wrappedList = (!!) <$> wrappedInt <*> wrappedList
So you don't need to unwrap anything or get values out, the operators<$> and <*> let you do what you like inside.
nth (Just 3) (Just "Hello") == 'l'
Here's a hint:
foo :: Applicative f => f Int -> f Int -> f Int
foo fx fy = (+) <$> fx <*> fy -- apply + "under" the functor
bar :: Applicative f => f a -> f [a] -> f [a]
bar fx fxs = ??? <$> fx <*> fxs -- apply ??? "under" the functor
sequenceA' :: Applicative f => [f a] -> f [a]
sequenceA' [] = pure [] -- as in your solution
sequenceA' (x:xs) = let y = x -- :: f a
ys = sequenceA' xs -- :: f [a]
in ???
I use let in the last function to clarify the types which are involved. After you fill in the ??? you can of course remove the let.
You can extract a from f a with pattern matching or evaluation, if f is not IO
import Control.Applicative
import System.IO
import Control.Monad.ST
-- with AndrewC sequenceA' definition
sequenceA' :: (Applicative f) => [f a] -> f [a]
sequenceA' [] = pure []
sequenceA' (c:cs) = (:) <$> c <*> sequenceA' cs
seqOfMaybes :: [Maybe a] -> [a]
seqOfMaybes listOfMb = case sequenceA' listOfMb of
Nothing -> []
Just list -> list
-- sequencing ST computations
compute :: a -> ST s a
compute x = return x
seqOfSTData :: [Int] -> [Int]
seqOfSTData vals = runST $ (sequenceA' (map compute vals) :: ST s [Int])
-- but you cannot escape the applicative f if f is IO
readAnInt :: IO Int
readAnInt = putStrLn "give me an Int>" >> hFlush stdout >> getLine >>= (return . read)
seqOfIO :: [IO a] -> IO [a]
seqOfIO listOfIO = sequenceA' listOfIO
main :: IO ()
main = do
print $ seqOfMaybes [Just 3, Just 4, Just 5]
print $ seqOfSTData [1,2,3]
seqOfIO [readAnInt, readAnInt] >>= print

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

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.

How do I handle an infinite list of IO objects in Haskell?

I'm writing a program that reads from a list of files. The each file either contains a link to the next file or marks that it's the end of the chain.
Being new to Haskell, it seemed like the idiomatic way to handle this is is a lazy list of possible files to this end, I have
getFirstFile :: String -> DataFile
getNextFile :: Maybe DataFile -> Maybe DataFile
loadFiles :: String -> [Maybe DataFile]
loadFiles = iterate getNextFile . Just . getFirstFile
getFiles :: String -> [DataFile]
getFiles = map fromJust . takeWhile isJust . loadFiles
So far, so good. The only problem is that, since getFirstFile and getNextFile both need to open files, I need their results to be in the IO monad. This gives the modified form of
getFirstFile :: String -> IO DataFile
getNextFile :: Maybe DataFile -> IO (Maybe DataFile)
loadFiles :: String -> [IO Maybe DataFile]
loadFiles = iterate (getNextFile =<<) . Just . getFirstFile
getFiles :: String -> IO [DataFile]
getFiles = liftM (map fromJust . takeWhile isJust) . sequence . loadFiles
The problem with this is that, since iterate returns an infinite list, sequence becomes an infinite loop. I'm not sure how to proceed from here. Is there a lazier form of sequence that won't hit all of the list elements? Should I be rejiggering the map and takeWhile to be operating inside the IO monad for each list element? Or do I need to drop the whole infinite list process and write a recursive function to terminate the list manually?
A step in the right direction
What puzzles me is getNextFile. Step into a simplified world with me, where we're not dealing with IO yet. The type is Maybe DataFile -> Maybe DataFile. In my opinion, this should simply be DataFile -> Maybe DataFile, and I will operate under the assumption that this adjustment is possible. And that looks like a good candidate for unfoldr. The first thing I am going to do is make my own simplified version of unfoldr, which is less general but simpler to use.
import Data.List
-- unfoldr :: (b -> Maybe (a,b)) -> b -> [a]
myUnfoldr :: (a -> Maybe a) -> a -> [a]
myUnfoldr f v = v : unfoldr (fmap tuplefy . f) v
where tuplefy x = (x,x)
Now the type f :: a -> Maybe a matches getNextFile :: DataFile -> Maybe DataFile
getFiles :: String -> [DataFile]
getFiles = myUnfoldr getNextFile . getFirstFile
Beautiful, right? unfoldr is a lot like iterate, except once it hits Nothing, it terminates the list.
Now, we have a problem. IO. How can we do the same thing with IO thrown in there? Don't even think about The Function Which Shall Not Be Named. We need a beefed up unfoldr to handle this. Fortunately, the source for unfoldr is available to us.
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
unfoldr f b =
case f b of
Just (a,new_b) -> a : unfoldr f new_b
Nothing -> []
Now what do we need? A healthy dose of IO. liftM2 unfoldr almost gets us the right type, but won't quite cut it this time.
An actual solution
unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> m [a]
unfoldrM f b = do
res <- f b
case res of
Just (a, b') -> do
bs <- unfoldrM f b'
return $ a : bs
Nothing -> return []
It is a rather straightforward transformation; I wonder if there is some combinator that could accomplish the same.
Fun fact: we can now define unfoldr f b = runIdentity $ unfoldrM (return . f) b
Let's again define a simplified myUnfoldrM, we just have to sprinkle in a liftM in there:
myUnfoldrM :: Monad m => (a -> m (Maybe a)) -> a -> m [a]
myUnfoldrM f v = (v:) `liftM` unfoldrM (liftM (fmap tuplefy) . f) v
where tuplefy x = (x,x)
And now we're all set, just like before.
getFirstFile :: String -> IO DataFile
getNextFile :: DataFile -> IO (Maybe DataFile)
getFiles :: String -> IO [DataFile]
getFiles str = do
firstFile <- getFirstFile str
myUnfoldrM getNextFile firstFile
-- alternatively, to make it look like before
getFiles' :: String -> IO [DataFile]
getFiles' = myUnfoldrM getNextFile <=< getFirstFile
By the way, I typechecked all of these with data DataFile = NoClueWhatGoesHere, and the type signatures for getFirstFile and getNextFile, with their definitions set to undefined.
[edit] changed myUnfoldr and myUnfoldrM to behave more like iterate, including the initial value in the list of results.
[edit] Additional insight on unfolds:
If you have a hard time wrapping your head around unfolds, the Collatz sequence is possibly one of the simplest examples.
collatz :: Integral a => a -> Maybe a
collatz 1 = Nothing -- the sequence ends when you hit 1
collatz n | even n = Just $ n `div` 2
| otherwise = Just $ 3 * n + 1
collatzSequence :: Integral a => a -> [a]
collatzSequence = myUnfoldr collatz
Remember, myUnfoldr is a simplified unfold for the cases where the "next seed" and the "current output value" are the same, as is the case for collatz. This behavior should be easy to see given myUnfoldr's simple definition in terms of unfoldr and tuplefy x = (x,x).
ghci> collatzSequence 9
[9,28,14,7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]
More, mostly unrelated thoughts
The rest has absolutely nothing to do with the question, but I just couldn't resist musing. We can define myUnfoldr in terms of myUnfoldrM:
myUnfoldr f v = runIdentity $ myUnfoldrM (return . f) v
Look familiar? We can even abstract this pattern:
sinkM :: ((a -> Identity b) -> a -> Identity c) -> (a -> b) -> a -> c
sinkM hof f = runIdentity . hof (return . f)
unfoldr = sinkM unfoldrM
myUnfoldr = sinkM myUnfoldrM
sinkM should work to "sink" (opposite of "lift") any function of the form
Monad m => (a -> m b) -> a -> m c.
since the Monad m in those functions can be unified with the Identity monad constraint of sinkM. However, I don't see anything that sinkM would actually be useful for.
sequenceWhile :: Monad m => (a -> Bool) -> [m a] -> m [a]
sequenceWhile _ [] = return []
sequenceWhile p (m:ms) = do
x <- m
if p x
then liftM (x:) $ sequenceWhile p ms
else return []
Yields:
getFiles = liftM (map fromJust) . sequenceWhile isJust . loadFiles
As you have noticed, IO results can't be lazy, so you can't (easily) build an infinite list using IO. There is a way out, however, in unsafeInterleaveIO; with this, you can do something like:
ioList startFile = do
v <- processFile startFile
continuation <- unsafeInterleaveIO (nextFile startFile >>= ioList)
return (v:continuation)
It's important to be careful here, though - you've just deferred the results of ioList to some unpredictable time in the future. It may never be run at all, in fact. So be very careful when you're being Clever™ like this.
Personally, I would just build a manual recursive function.
Laziness and I/O are a tricky combination. Using unsafeInterleaveIO is one way to produce lazy lists in the IO monad (and this is the technique used by the standard getContents, readFile and friends). However, as convenient as this is, it exposes pure code to possible I/O errors and makes makes releasing resources (such as file handles) non-deterministic. This is why most "serious" Haskell applications (especially those concerned with efficiency) nowadays use things called Enumerators and Iteratees for streaming I/O. One library in Hackage that implements this concept is enumerator.
You are probably fine with using lazy I/O in your application, but I thought I'd still give this as an example of another way to approach these kind of problems. You can find more in-depth tutorials about iteratees here and here.
For example, your stream of DataFiles could be implemented as an Enumerator like this:
import Data.Enumerator
import Control.Monad.IO.Class (liftIO)
iterFiles :: String -> Enumerator DataFile IO b
iterFiles s = first where
first (Continue k) = do
file <- liftIO $ getFirstFile s
k (Chunks [file]) >>== next file
first step = returnI step
next prev (Continue k) = do
file <- liftIO $ getNextFile (Just prev)
case file of
Nothing -> k EOF
Just df -> k (Chunks [df]) >>== next df
next _ step = returnI step

Mapping over IO in 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_.

Resources