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

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

Related

Good practice to write to a file

In the main function of my program, I call timesRule which is returning a Boolean value. In this function I want to write to a file. However, if I understood correctly the function times rule needs to return IO() if it writes to file.
How should I structure my code to write to a file in a function returning a Boolean value ?
timesRule :: (MultiSet LocalType) -> Bool
timesRule sequent = do
let result = MultiSet.concatMap (\x -> if isPrl x then [checkTimes x, checkTimes2 x] else [x] ) sequent
let file = "tmp/log.txt"
let content = "TIMES rule: " ++ (show(MultiSet.toList result))
let log = writeToFile file content
prefixRule result
Used function:
import qualified System.IO.Strict as SIO
writeToFile :: FilePath -> String -> IO()
writeToFile file content = do
x <- SIO.readFile file
writeFile file ("\n"++content)
appendFile file x
The somewhat obvious solution would be changing the type your function to IO Bool as #Robin Zigmond pointed out.
There is some problem with your syntax apart from calling writeToFile, though. For your function timesRule to have the given type it would need to look like this:
timesRule :: (MultiSet LocalType) -> Bool
timesRule sequent = -- there is no do here
let
result = MultiSet.concatMap (\x -> if isPrl x then [checkTimes x, checkTimes2 x] else [x] ) sequent
-- the following two lines are superfluous ...
file = "tmp/log.txt"
content = "TIMES rule: " ++ (show(MultiSet.toList result))
-- ... because this still doesn't work
log = writeToFile file content
-- ... and what were you going to use `log` for, anyway?
in
prefixRule result
Changing your type to IO Bool allows you to use monadic do-syntax. Bool by itself neither has an applicative nor a monad instance and thus there is no meaningful do-syntax. (In order to have either an applicative or a monad instance, you need a type function like Maybe or IO, fyi):
timesRule :: (MultiSet LocalType) -> IO Bool
timesRule sequent = do
let
result = MultiSet.concatMap (\x -> if isPrl x then [checkTimes x, checkTimes2 x] else [x] ) sequent
file = "tmp/log.txt"
content = "TIMES rule: " ++ (show(MultiSet.toList result))
-- the syntax to get the value of type `a` out of `IO a` is this:
log <- writeToFile file content
-- the function to turn a value of type `a` into `IO a` is `pure`:
pure (prefixRule result)
You stil don't use log and might as well replace
log <- writeToFile file content
with
writeToFile file content
Given that writeToFile has type ... -> IO (), the () is pronounced "unit", the value of log is () and thus log does not contain any useful information (probably).
The less obvious solution is to refactor your code a bit and seperate the concerns. Sometimes it does make sense to have a function write to a file and return some boolean value. In your case, you probably want a funcion that returns result, i.e. turn this line into a function:
MultiSet.concatMap (\x -> if isPrl x then [checkTimes x, checkTimes2 x] else [x] ) sequent
Then you already have prefixRule that gives you the Bool and you have writeFile. This way you separate pure code (anything that does not have the type IO something) form code with IO-side effects.

How to use readFile

I am having trouble reading in a level file in Haskell. The goal is to read in a simple txt file with two numbers seperated by a space and then commas. The problem I keep getting is this: Couldn't match type `IO' with `[]'
If I understand correctly the do statement is supposed to pull the String out of the Monad.
readLevelFile :: FilePath -> [FallingRegion]
readLevelFile f = do
fileContent <- readFile f
(map lineToFallingRegion (lines fileContent))
lineToFallingRegion :: String -> FallingRegion
lineToFallingRegion s = map textShapeToFallingShape (splitOn' (==',') s)
textShapeToFallingShape :: String -> FallingShape
textShapeToFallingShape s = FallingShape (read $ head numbers) (read $ head
$ tail numbers)
where numbers = splitOn' (==' ') s
You can't pull things out of IO. You can think of IO as a container (in fact, some interpretations of IO liken it to the box containing Schrödinger's cat). You can't see what's in the container, but if you step into the container, values become visible.
So this should work:
readLevelFile f = do
fileContent <- readFile f
return (map lineToFallingRegion (lines fileContent))
It does not, however, have the type given in the OP. Inside the do block, fileContent is a String value, but the entire block is still inside the IO container.
This means that the return type of the function isn't [FallingRegion], but IO [FallingRegion]. So if you change the type annotation for readLevelFile to
readLevelFile :: FilePath -> IO [FallingRegion]
you should be able to get past the first hurdle.
Let's look at your first function with explicit types:
readLevelFile f = do
(fileContent :: String) <-
(readFile :: String -> IO String) (f :: String) :: IO String
fileContent is indeed of type String but is only available within the execution of the IO Monad under which we are evaluating. Now what?
(map lineToFallingRegion (lines fileContent)) :: [String]
Now you are suddenly using an expression that is not an IO monad but instead is a list value - since lists are also a type of monad the type check tries to unify IO with []. What you actually wanted is to return this value:
return (map lineToFallingRegion (lines fileContent)) :: IO [String]
Now recalling that we can't ever "exit" the IO monad your readLevelFile type must be IO - an honest admission that it interacts with the outside world:
readLevelFile :: FilePath -> IO [FallingRegion]

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

Haskell: Hiding failures in lazy IO

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.

How do I combine IOError exceptions with locally relevant exceptions?

I am building a Haskell application and trying to figure out how I am going to build the error handling mechanism. In the real application, I'm doing a bunch of work with Mongo. But, for this, I'm going to simplify by working with basic IO operations on a file.
So, for this test application, I want to read in a file and verify that it contains a proper fibonnacci sequence, with each value separated by a space:
1 1 2 3 5 8 13 21
Now, when reading the file, any number of things could actually be wrong, and I am going to call all of those exceptions in the Haskell usage of the word.
data FibException = FileUnreadable IOError
| FormatError String String
| InvalidValue Integer
| Unknown String
instance Error FibException where
noMsg = Unknown "No error message"
strMsg = Unknown
Writing a pure function that verifies the sequence and throws an error in the case that the sequence is invalid is easy (though I could probably do better):
verifySequence :: String -> (Integer, Integer) -> Either FibException ()
verifySequence "" (prev1, prev2) = return ()
verifySequence s (prev1, prev2) =
let readInt = reads :: ReadS Integer
res = readInt s in
case res of
[] -> throwError $ FormatError s
(val, rest):[] -> case (prev1, prev2, val) of
(0, 0, 1) -> verifySequence rest (0, 1)
(p1, p2, val') -> (if p1 + p2 /= val'
then throwError $ InvalidValue val'
else verifySequence rest (p2, val))
_ -> throwError $ InvalidValue val
After that, I want the function that reads the file and verifies the sequence:
type FibIOMonad = ErrorT FibException IO
verifyFibFile :: FilePath -> FibIOMonad ()
verifyFibFile path = do
sequenceStr <- liftIO $ readFile path
case (verifySequence sequenceStr (0, 0)) of
Right res -> return res
Left err -> throwError err
This function does exactly what I want if the file is in the invalid format (it returns Left (FormatError "something")) or if the file has a number out of sequence (Left (InvalidValue 15)). But it throws an error if the file specified does not exist.
How do I catch the IO errors that readFile may produce so that I can transform them into the FileUnreadable error?
As a side question, is this even the best way to do it? I see the advantage that the caller of verifyFibFile does not have to set up two different exception handling mechanisms and can instead catch just one exception type.
You might consider EitherT and the errors package in general. http://hackage.haskell.org/packages/archive/errors/1.3.1/doc/html/Control-Error-Util.html has a utility tryIO for catching IOError in EitherT and you could use fmapLT to map error values to your custom type.
Specifically:
type FibIOMonad = EitherT FibException IO
verifyFibFile :: FilePath -> FibIOMonad ()
verifyFibFile path = do
sequenceStr <- fmapLT FileUnreadable (tryIO $ readFile path)
hoistEither $ verifySequence sequenceStr (0, 0)
#Savanni D'Gerinel: you are on the right track. Let's extract your error-catching code from verifyFibFile to make it more generic, and modify it slightly so that it works directly in ErrorT:
catchError' :: ErrorT e IO a -> (IOError -> ErrorT e IO a) -> ErrorT e IO a
catchError' m f =
ErrorT $ catchError (runErrorT m) (fmap runErrorT f)
verifyFibFile can now be written as:
verifyFibFile' :: FilePath -> FibIOMonad ()
verifyFibFile' path = do
sequenceStr <- catchError' (liftIO $ readFile path) (throwError . FileUnReadable)
ErrorT . return $ verifySequence sequenceStr' (0, 0)
Notice what we have done in catchError'. We have stripped the ErrorT constructor from the ErrorT e IO a action, and also from the return value of the error-handling function, knowing than we can reconstruct them afterwards by wrapping the result of the control operation in ErrorT again.
Turns out that this is a common pattern, and it can be done with monad transformers other than ErrorT. It can get tricky though (how to do this with ReaderT for example?). Luckily, the monad-control packgage already provides this functionality for many common transformers.
The type signatures in monad-control can seem scary at first. Start by looking at just one function: control. It has the type:
control :: MonadBaseControl b m => (RunInBase m b -> b (StM m a)) -> m a
Let's make it more specific by making b be IO:
control :: MonadBaseControl IO m => (RunInBase m IO -> IO (StM m a)) -> m a
m is a monad stack built on top of IO. In your case, it would be ErrorT IO.
RunInBase m IO is a type alias for a magical function, that takes a value of type m a and returns a value of type IO *something*, something being some complex magic that encodes the state of the whole monad stack inside IO and lets you reconstruct the m a value afterwards, once you have "fooled" the control operation that only accepts IO values. control provides you with that function, and also handles the reconstruction for you.
Applying this to your problem, we rewrite verifyFibFile once more as:
import Control.Monad.Trans.Control (control)
import Control.Exception (catch)
verifyFibFile'' :: FilePath -> FibIOMonad ()
verifyFibFile'' path = do
sequenceStr <- control $ \run -> catch (run . liftIO $ readFile path)
(run . throwError . FileUnreadable)
ErrorT . return $ verifySequence sequenceStr' (0, 0)
Keep in mind that this only works when the proper instance of MonadBaseControl b m exists.
Here is a nice introduction to monad-control.
So, here's an answer that I have developed. It centers around getting readFile wrapped into the proper catchError statement, and then lifted.
verifyFibFile :: FilePath -> FibIOMonad ()
verifyFibFile path = do
contents <- liftIO $ catchError (readFile path >>= return . Right) (return . Left . FileUnreadable)
case contents of
Right sequenceStr' -> case (verifySequence sequenceStr' (0, 0)) of
Right res -> return res
Left err -> throwError err
Left err -> throwError err
So, verifyFibFile gets a little more nested in this solution.
readFile path has type IO String, obviously. In this context, the type for catchError will be:
catchError :: IO String -> (IOError -> IO String) -> IO String
So, my strategy was to catch the error and turn it into the left side of an Either, and turn the successful value into the right side, changing my data type to this:
catchError :: IO (Either FibException String) -> (IOError -> IO (Either FibException String)) -> IO (Either FibException String)
I do this by, in the first parameter, simply wrapping the result into Right. I figure that I won't actually execute the return . Right branch of the code unless readFile path was successful. In the other parameter to catch, I start with an IOError, wrap it in Left, and then return it back into the IO context. After that, no matter what the result is, I lift the IO value up into the FibIOMonad context.
I'm bothered by the fact that the code gets even more nested. I have Left values, and all of those Left values get thrown. I'm basically in an Either context, and I had thought that one of the benefits Either's implementation of the Monad class was that Left values would simply be passed along through the binding operations and that no further code in that context would be executed. I would love some elucidation on this, or to see how the nesting can be removed from this function.
Maybe it can't. It does seem that the caller, however, can call verifyFibFile repeatedly and execution basically stops the first time verifyFibFile returns an error. This works:
runTest = do
res <- verifyFibFile "goodfib.txt"
liftIO $ putStrLn "goodfib.txt"
--liftIO $ printResult "goodfib.txt" res
res <- verifyFibFile "invalidValue.txt"
liftIO $ putStrLn "invalidValue.txt"
res <- verifyFibFile "formatError.txt"
liftIO $ putStrLn "formatError.txt"
Main> runErrorT $ runTest
goodfib.txt
Left (InvalidValue 17)
Given the files that I have created, both invalidValue.txt and formatError.txt cause errors, but this function returns Left (InvalidValue ...) for me.
That's okay, but I still feel like I've missed something with my solution. And I have no idea whether I'll be able to translate this into something that makes MongoDB access more robust.

Resources