Haskell: Hiding failures in lazy IO - haskell

This is a noob question.
I'd like to write a function which provides a lazy stream of images, presumably something like:
imageStream :: [IO Image]
Unfortunately, the function which reads images can fail, so it looks like:
readImage :: IO (Maybe Image)
So, the function I can write looks like:
maybeImageStream :: [IO (Maybe Image)]
How do I implement a function such as the following, while still keeping lazy IO?
flattenImageStream :: [IO (Maybe Image)] -> [IO Image]
Semantically, when you ask flattenImageStream for the next image, it should iterate through the list and attempt to read each image. It does this until it finds an image that loads, and returns it.
EDIT: There seems to be some disagreement in the answers.
Some have suggested solutions that use sequence, but I'm pretty sure I tested that and found it destroys laziness.
(I'll test it again to be sure when I get back to my computer.)
Someone also suggested using unsafeInterleaveIO.
From the documentation for that function, it seems it would work, but obviously I want to respect the type system as much as possible.

You can use ListT from pipes, which provides a safer alternative to lazy IO that does the right thing in this case.
The way you model your lazy stream of potentially failing images is:
imageStream :: ListT IO (Maybe Image)
Assuming that you had some image loading function of type:
loadImage :: FileName -> IO (Maybe Image)
.. then the way you build such a stream would be something like:
imageStream = do
fileName <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"]
lift $ loadImage fileName
If you use the dirstream library, then you can even lazily stream over the directory contents, too.
The function that filters out only the successful results would have this type:
flattenImageStream :: (Monad m) => ListT m (Maybe a) -> ListT m a
flattenImageStream stream = do
ma <- stream
case ma of
Just a -> return a
Nothing -> mzero
Notice that this function works for any base monad, m. There is nothing IO-specific about it. It also preserves laziness!
Applying flattenImage to imageStream, gives us something of type:
finalStream :: List IO Image
finalStream = flattenImage imageStream
Now let's say that you have some function that consumes these images, of type:
useImage :: Image -> IO ()
If you want to process the final ListT using the useImage function, you just write:
main = runEffect $
for (every finalStream) $ \image -> do
lift $ useImage image
That will then lazily consume the image stream.
Of course, you could also play code golf and combine all of that into the following much shorter version:
main = runEffect $ for (every image) (lift . useImage)
where
image = do
fileName <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"]
maybeImage <- lift $ loadImage fileName
case maybeImage of
Just img -> return img
Nothing -> mzero
I'm also thinking of adding a fail definition for ListT so that you could just write:
main = runEffect $ for (every image) (lift . useImage)
where
image = do
fileName <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"]
Just img <- lift $ loadImage fileName
return img

as suggested u can turn [m a] into m [a] using sequence
so you get:
imageStream :: IO [Image]
then you can use cayMaybes from Data.Maybe to keep just the Just values:
catMaybes `liftM` imageStream

Implementing this as requested seems like it would require knowing outside of the IO monad whether a value inside IO was Nothing, and as IO is designed to prevent its values from "leaking out" into the outside purely functional world (unsafePerformIO notwithstanding), this would be impossible. Instead, I recommend producing an IO [Image]: use sequence to convert the [IO (Maybe Image)] to IO [Maybe Image], and then use Data.Maybe.catMaybes within the IO monad (e.g., with fmap or liftM) to convert to IO [Image], e.g.:
flattenImageStream = fmap catMaybes $ sequence maybeImageStream

I don't think any of these other answers are doing exactly what you want. Because i'm pretty sure catMaybes will just skip over the image and not try to reload it. If you want to just keep trying to reload an image try this.
flattenImageStream :: [IO (Maybe Image)] -> IO [Image]
flattenImageStream xs = mapM untilSuc xs
untilSuc :: IO (Maybe a) -> IO a
untilSuc f = do
res <- f
case res of
Nothing -> untilSuc f
Just i -> return i
But what you are doing is kind of strange. What if you have the wrong file path? What if the image simply can't be loaded? You'll just try to load an image forever. You should probably have a number of times to try and load the image before it gives up.

Related

Is it possible to use writeFile inside out of the main function (in haskell)?

I am still a beginner in Haskell, so after reading some writefile tutorials online, I see most of the writefile examples online are used inside the main function (main = IO ())
I am wondering whether it's possible to write a function that writes the results into a file using writefile when it is computed? In some programs (especially games), users might want to stop at a particular points of the game by saving the contents into a .txt file.
For example something like this: (this function does not work, just wondering how to make it work)
concat :: FilePath -> [[a]] -> [a]
concat txt [] = []`
concat txt (xs : xss) = do
y <- xs ++ concat xss
writeFile txt (unlines y)
Thanks:)
The writeFile function has the type FilePath -> String -> IO (), which means that it must run in the IO context.
It doesn't have to run in the main function, but any function that involves IO, including writeFile, will have a return type that involves IO. So you could definitely do something like this:
myFunc :: String -> IO ()
myFunc contents = do
-- do something else
writeFile "foo.txt" contents
-- do more stuff here
You can't, however, call functions that return IO a from pure functions (or, rather, you can't extract the value from the IO container). That's by design; it's how Haskell works, and it's a good thing. If you want to enable users to perform impure actions at arbitrary times, you must design for such a feature. Here's my introduction to pure interactions - that's one place to start.
Yes, you can use writeFile in other places than main, but for a place to qualify, the type IO has to be a part of that place's type signature. (The reason I'm saying place is because main isn't a function, but your concat is a function. And the place you want to look at putting your writeFile call has to be an IO action, which can be the result of a function or not.)
You mentioned saving something related to a game into a .txt file. An example of that could be:
saveGame :: FilePath -> GameState -> IO ()
saveGame gameFile gameState =
writeFile gameFile (serializeGame gameState)
serializeGame :: GameState -> String
serializeGame (GameState ...) = ...
runGame :: GameState -> IO ()
runGame gameState = do
...
if wantsToSaveGame
then saveGame gameFile gameState
else ...
...
runGame updatedGameState
main :: IO ()
main = do
...
runGame initialGameState
In this contrived example, serializeGame would not be a suitable place to call saveGame because it's a pure function, whereas runGame is a self-recursive IO () action capable of affecting files on your file system.
An example of a related IO action that isn't a function could be this one:
resetSaveGame :: IO ()
resetSaveGame =
saveGame defaultGameFile initialGameState

Monad transformers with IO and Maybe

I am trying to stack up IO and Maybe monads but either I don't understand monad transformers well enough or this is not possible using transformers. Can some one help me understand this?
f :: String -> Maybe String
main :: IO ()
main = do
input <- getLine -- IO String
output <- f input -- Maybe String (Can't extract because it is IO do block)
writeFile "out.txt" output -- gives error because writeFile expects output :: String
In the above simplified example, I have a function f that returns a Maybe String and I would like to have a neat way of extracting this in the IO do block. I tried
f :: String -> MaybeT IO String
main :: IO ()
main = do
input <- getLine -- IO String
output <- runMaybeT (f input) -- Extracts output :: Maybe String instead of String
writeFile "out.txt" output -- gives error because writeFile expects output :: String
which lets me extract the Maybe String out in the second line of do block but I need to extract the string out of that. Is there a way to do this without using case?
Let's stick for a moment with your first snippet. If f input is a Maybe String, and you want to pass its result to writeFile "out.txt", which takes a String, you need to deal with the possibility of f input being Nothing. You don't have to literally use a case-statement. For instance:
maybe from the Prelude is case analysis packaged as a function;
fromMaybe from Data.Maybe lets you easily supply a default value, if that makes sense for your use case;
traverse_ and for_ from Data.Foldable could be used to silently ignore Nothing-ness:
for_ (f input) (writeFile "out.txt") -- Does nothing if `f input` is `Nothing`.
Still, no matter what you choose to do, it will involve handling Nothing somehow.
As for MaybeT, you don't really want monad transformers here. MaybeT IO is for when you want something like a Maybe computation but in which you can also include IO computations. If f :: String -> Maybe String already does what you want, you don't need to add an underlying IO layer to it.

Haskell using IO on a function that doesn't expect it

Question:
How do I give an "IO SDL.Surface" to a function that expects an "SDL.Surface"?
I'd rather rethink my entire approach than resort to using something like "unsafePerformIO", unless this is actually the correct time to use it (which I doubt).
Further info:
I had a file filled with numbers and filepaths and I've parsed this file and loaded the images located at these paths into a list [(Int, IO SDL.Surface)]. Problem is, that the SDL.blitSurface function expects a normal SDL.Surface.
Error message:
Couldn't match type `IO SDL.Surface'
with `GHC.ForeignPtr.ForeignPtr SDL.SurfaceStruct'
Expected type: SDL.Surface
Actual type: IO SDL.Surface
I'm not sure that source code is necessary to answer the question, but I'll provide some anyway just in case it helps:
To load an image file I use:
loadImage :: FilePath -> IO SDL.Surface
loadImage [] = error "empty list"
loadImage a =
SDL.loadBMP a
To create the list of numbers and images I use:
createIDImageList :: [Tiletype] -> [(Int, IO SDL.Surface)]
createIDImageList a =
if null a then []
else [(tiletypeid $ a !! 0, loadImage (C8.unpack ( tiletypeimage ( a !! 0))))] ++ createIDImageList (tail a)
To retrieve the correct picture from this list, I use this function:
imageFromID :: Int -> [(Int, IO SDL.Surface)] -> Maybe (IO SDL.Surface)
imageFromID a b =
if null b then Nothing
else if a == (fst $ b !! 0) then Just (snd $ b !! 0)
else imageFromID a (tail b)
And finally I use the imageFromID with the SDL.blitSurface to draw the image, except that I can't due to IO.
Any time you end up with [IO Foobar], what you probably want is actually IO [Foobar]. The sequence function transforms one into the other. Or you can use mapM instead of map when creating the list in the first place.
In your example, it's a little more complicated, since we have [(Int, IO Surface)]. Let me see what I can suggest...
loadImage is an I/O action. It takes a filename and returns an IO action to load the image. Your createIDImageList function is really
createIDImageList = map f
where
f a = (tiletypeid a, loadImage (C8.unpack ( tiletypeimage a) ) )
What you probably want to do is change f to have type IO (Int, Surface) rather than (Int, IO Surface). And then you can mapM f, yielding a single I/O action that returns a list of stuff.
createIDImageList :: [Tiletype] -> IO [(Int, SDL.Surface)]
createIDImageList = mapM f
where
f a = do
surface <- loadImage (C8.unpack (tiletypeimage a) )
return (tiletypeid a, surface)
Regarding imageFromID: what you probably want to do is something like this:
main = do
images <- createIDImageList (...)
...
let image5 = imageFromID 5 images
SDL.blitSurface image5 ...
The type of imageFromID then becomes
imageFromID :: `Int -> [(Int, SDL.Surface)] -> Maybe SDL.Surface
(Since images now has type [(Int, SDL.Surface)], with no IO in it, thanks to <-.)
What you're doing here is that createIDImageList is actually loading everything off disk, and then you can use imageFromID (which has no I/O in it) whenever you want to get the surface you're interested in.
do image <- loadImage "imagefile"
blitSurface image rect1 dest rect2

After reading a file I have IO [Char], but I need [IO Char]

I have a file number.txt which contains a large number and I read it into an IO String like this:
readNumber = readFile "number.txt" >>= return
In another function I want to create a list of Ints, one Int for each digit…
Lets assume the content of number.txt is:
1234567890
Then I want my function to return [1,2,3,4,5,6,7,8,9,0].
I tried severall versions with map, mapM(_), liftM, and, and, and, but I got several error messages everytime, which I was able to reduce to
Couldn't match expected type `[m0 Char]'
with actual type `IO String'
The last version I have on disk is the following:
module Main where
import Control.Monad
import Data.Char (digitToInt)
main = intify >>= putStrLn . show
readNumber = readFile "number.txt" >>= return
intify = mapM (liftM digitToInt) readNumber
So, as far as I understand the error, I need some function that takes IO [a] and returns [IO a], but I was not able to find such thing with hoogle… Only the other way round seemes to exist
In addition to the other great answers here, it's nice to talk about how to read [IO Char] versus IO [Char]. In particular, you'd call [IO Char] "an (immediate) list of (deferred) IO actions which produce Chars" and IO [Char] "a (deferred) IO action producing a list of Chars".
The important part is the location of "deferred" above---the major difference between a type IO a and a type a is that the former is best thought of as a set of instructions to be executed at runtime which eventually produce an a... while the latter is just that very a.
This phase distinction is key to understanding how IO values work. It's also worth noting that it can be very fluid within a program---functions like fmap or (>>=) allow us to peek behind the phase distinction. As an example, consider the following function
foo :: IO Int -- <-- our final result is an `IO` action
foo = fmap f getChar where -- <-- up here getChar is an `IO Char`, not a real one
f :: Char -> Int
f = Data.Char.ord -- <-- inside here we have a "real" `Char`
Here we build a deferred action (foo) by modifying a deferred action (getChar) by using a function which views a world that only comes into existence after our deferred IO action has run.
So let's tie this knot and get back to the question at hand. Why can't you turn an IO [Char] into an [IO Char] (in any meaningful way)? Well, if you're looking at a piece of code which has access to IO [Char] then the first thing you're going to want to do is sneak inside of that IO action
floob = do chars <- (getChars :: IO [Char])
...
where in the part left as ... we have access to chars :: [Char] because we've "stepped into" the IO action getChars. This means that by this point we've must have already run whatever runtime actions are required to generate that list of characters. We've let the cat out of the monad and we can't get it back in (in any meaningful way) since we can't go back and "unread" each individual character.
(Note: I keep saying "in any meaningful way" because we absolutely can put cats back into monads using return, but this won't let us go back in time and have never let them out in the first place. That ship has sailed.)
So how do we get a type [IO Char]? Well, we have to know (without running any IO) what kind of IO operations we'd like to do. For instance, we could write the following
replicate 10 getChar :: [IO Char]
and immediately do something like
take 5 (replicate 10 getChar)
without ever running an IO action---our list structure is immediately available and not deferred until the runtime has a chance to get to it. But note that we must know exactly the structure of the IO actions we'd like to perform in order to create a type [IO Char]. That said, we could use yet another level of IO to peek at the real world in order to determine the parameters of our action
do len <- (figureOutLengthOfReadWithoutActuallyReading :: IO Int)
return $ replicate len getChar
and this fragment has type IO [IO Char]. To run it we have to step through IO twice, we have to let the runtime perform two IO actions, first to determine the length and then second to actually act on our list of IO Char actions.
sequence :: [IO a] -> IO [a]
The above function, sequence, is a common way to execute some structure containing a, well, sequence of IO actions. We can use that to do our two-phase read
twoPhase :: IO [Char]
twoPhase = do len <- (figureOutLengthOfReadWithoutActuallyReading :: IO Int)
putStrLn ("About to read " ++ show len ++ " characters")
sequence (replicate len getChar)
>>> twoPhase
Determining length of read
About to read 22 characters
let me write 22 charac"let me write 22 charac"
You got some things mixed up:
readNumber = readFile "number.txt" >>= return
the return is unecessary, just leave it out.
Here is a working version:
module Main where
import Data.Char (digitToInt)
main :: IO ()
main = intify >>= print
readNumber :: IO String
readNumber = readFile "number.txt"
intify :: IO [Int]
intify = fmap (map digitToInt) readNumber
Such a function can't exists, because you would be able to evaluate the length of the list without ever invoking any IO.
What is possible is this:
imbue' :: IO [a] -> IO [IO a]
imbue' = fmap $ map return
Which of course generalises to
imbue :: (Functor f, Monad m) => m (f a) -> m (f (m a))
imbue = liftM $ fmap return
You can then do, say,
quun :: IO [Char]
bar :: [IO Char] -> IO Y
main = do
actsList <- imbue quun
y <- bar actsLists
...
Only, the whole thing about using [IO Char] is pointless: it's completely equivalent to the much more straightforward way of working only with lists of "pure values", only using the IO monad "outside"; how to do that is shown in Markus's answer.
Do you really need many different helper functions? Because you may write just
main = do
file <- readFile "number.txt"
let digits = map digitToInt file
print digits
or, if you really need to separate them, try to minimize the amount of IO signatures:
readNumber = readFile "number.txt" --Will be IO String
intify = map digitToInt --Will be String -> [Int], not IO
main = readNumber >>= print . intify

Is there a way to unwrap a type from an IO monad?

I have this very simple function
import qualified Data.ByteString.Lazy as B
getJson :: IO B.ByteString
getJson = B.readFile jsonFile
readJFile :: IO (Maybe Response)
readJFile = parsing >>= (\d ->
case d of
Left err -> return Nothing
Right ps -> return (Just ps))
where parsing = fmap eitherDecode getJson :: IO (Either String Response)
where jsonFile is a path to a file on my harddrive (pardon the lack of do-notation, but I found this more clear to work with)
my question is; is there a way for me to ditch the IO part so I can work with the bytestring alone?
I know that you can pattern match on certain monads like Either and Maybe to get their values out, but can you do something similar with IO?
Or voiced differently: is there a way for me to make readJFile return Maybe Response without the IO?
To expand on my comments, here's how you can do it:
getJson :: IO B.ByteString
getJson = B.readFile jsonFile -- as before
readJFile :: B.ByteString -> Maybe Response -- look, no IO
readJFile b = case eitherDecode b of
Left err -> Nothing
Right ps -> Just ps
In the end, you combine everything in one IO action again:
getAndProcess :: IO (Maybe Response)
getAndProcess = do
b <- getJson
return (readJFile b)
You never need to "drag a monad" through any functions, unless they all need to actually do IO. Just lift the entire chain into the monad with fmap (or liftM / liftM2 / ...).
For instance,
f1 :: B.ByteString -> K
f2 :: K -> I
f3 :: K -> J
f4 :: I -> J -> M
and your entire thing is supposed to be like
m :: M
m = let k = "f1 getJson"
in f4 (f2 k) (f3 k)
The you can simply do
m = fmap (\b -> let k = f1 b
in f4 (f2 k) (f3 k) )
getJson
Incidentally, this might look nicer with do notation:
m = do
b <- getJson
return $ let k = f1 b
in f4 (f2 k) (f3 k)
Concerning you edit and the question
is there a way for me to make readJFile return Maybe Response without the IO?
No, that can't possibly work, because readJFile does need to do IO. There's no way escaping from the IO monad then, that's the whole point of it! (Well, there is unsafePerformIO as Ricardo says, but this is definitely not a valid application for it.)
If it's the clunkiness of unpacking Maybe values in the IO monad, and the signatures with parens in them, you may want to looks at the MaybeT transformer.
readJFile' :: MaybeT IO Response
readJFile' = do
b <- liftIO getJson
case eitherDecode b of
Left err -> mzero
Right ps -> return ps
No, there is no safe way to get a value out of the IO monad. Instead you should do the work inside the IO monad by applying functions with fmap or bind (>>=). Also you should use decode instead of eitherDecode when you want your result to be in Maybe.
getJson :: IO B.ByteString
getJson = B.readFile jsonFile
parseResponse :: B.ByteString -> Maybe Response
parseResponse = decode
readJFile :: IO (Maybe Response)
readJFile = fmap parseResponse getJSON
You could also use do notation if that is clearer to you:
readJFile :: IO (Maybe Response)
readJFile = do
bytestring <- getJson
return $ decode bytestring
Note that you dont even need the parseResponse function since readJFile specifies the type.
In general, yes, there is a way. Accompanied by a lot of "but", but there is. You're asking for what it's called an unsafe IO operation: System.IO.Unsafe. It's used to write wrappers when calling to external libraries usually, it's not something to resort to in regular Haskell code.
Basically, you can call unsafePerformIO :: IO a -> a which does exactly what you want, it strips out the IO part and gives you back wrapped value of type a. But, if you look at the documentation, there are a number of requirements which you should guarantee yourself to the system, which all end up in the same idea: even though you performed the operation via IO, the answer should be the result of a function, as expected from any other haskell function which does not operate in IO: it should always have the same result without side effects, only based on the input values.
Here, given your code, this is obviously NOT the case, since you're reading from a file. You should just continue working within the IO monad, by calling your readJFile from within another function with result type IO something. Then, you'll be able to read the value within the IO wrapper (being in IO yourself), work on it, and then re-wrap the result in another IO when returning.

Resources