Why does this IO-Handling not work (IO (Either a b)) - haskell

I'm trying to extract "a" and the error "b" from an expression of the type IO (Either a b).
I have this function, which returns a parsed file based on the file path
readFile' :: FilePath -> IO (Either a b)
And that's the way I'm trying to extract the values of a and b:
rFile :: FilePath -> String
rFile f = do
l <- readFile' f
case l of
Right n -> show n
Left m -> show m
This is the error message:
Couldn't match type `IO' with `[]'
Expected type: [Either a b]
Actual type: IO (Either a b)
* In a stmt of a 'do' block: l <- readFile' f

rFile can't return a String value, only an IO String value. (Or more precisely, the result of the do construct must be an IO String value, not a String.)
rFile :: FilePath -> IO String
rFile f = do
l <- readFile' f
return $ case l of
Right n -> show n
Left m -> show m
You can use fmap and either to get rid of both the explicit case analysis and the do syntax.
rFile f = fmap (either show show) (readFile' f)
(The obvious follow-up question, how do I get a String from an IO String, is one I'm not going to rehash here. For all practical intents and purposes, you don't.)

Related

How to read a file in a do block

I'm learning Haskell and I'm trying to figure out why I'm getting an error on the following piece of code. I'm trying to define a function that can read a file at a given location, and perform some function on it, but it has an error that I'm afraid I can't get my head around.
I imagine I'm doing something stupid but I can't figure out what; can someone tell me?
readAndProcessFile :: String -> (String -> a) -> a
readAndProcessFile l f = do
contents <- readFile l -- error here
let result = f contents
return result
I get the error:
Occurs check: cannot construct the infinite type: a ~ IO a
In a stmt of a 'do' block: contents <- readFile l
In the expression:
do contents <- readFile l
let result = (f contents)
return result
In an equation for ‘readAndProcessFile’:
readAndProcessFile l f
= do contents <- readFile l
let result = ...
return result
• Relevant bindings include
f :: String -> a
readAndProcessFile :: String -> (String -> a) -> a
the type of readAndProcessFile is String -> (String -> a) -> IO a. Indeed, you use a do block, so that means it is monadic. What you here basically write is readFile >>= \contents -> let result = f contents in return result. The readFile furthermore specializes this to an IO.
You can simplify the expression by making use of <$> :: Functor f => (a -> b) -> f a -> f b
readAndProcessFile :: FilePath -> (String -> a) -> IO a
readAndProcessFile l f = f <$> readFile l

Haskell IO-Monad error upon explicitly stating parameter for 'show'

Although I feel like a have a good understanding of Haskel IO and Monads, I am having a hard time understanding the following error message.
Consider the following simple function in Haskell
testf :: Show a => a -> String
testf x = show x
I tried implementing a variant that prints to the console by using an IO Monad
printtoscreen :: Show a => a -> IO()
printtoscreen x = putStrLn . show x
However, this yields the following error:
Couldn't match type ‘[Char]’ with ‘a0 -> String’
Expected type: a0 -> String
Actual type: String
The correct version should omit explicitly stating the x parameter
printtoscreen :: Show a => a -> IO()
printtoscreen = putStrLn . show
I understand why the last code snippet works, but I cannot make sense out of the error message of the second code snippet, considering that it will also return a string to putStrLn
So why should the xparameter be omitted in the IO() variant?
., the function composition operator, expects a function. show x however is not a function; it's an evaluated value (of type [Char]) by the time it's given to ..
You'd have to use the function application operator instead:
printtoscreen x = putStrLn $ show x
So why should the x parameter be omitted in the IO () variant?
This has nothing to do with IO () itself. You here use function composition. Indeed, the (.) :: (b -> c) -> (a -> b) -> a -> c function is defined as:
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)
It is thus used to combine two functions f and g in a new function that first applies g to a parameter, and then f to the result of g x.
If you write:
printtoscreen x = putStrLn . show x
then the (.) function will resolve this to:
printtoscreen x = \y -> putStrLn (show x y)
or thus easier to read:
printtoscreen x y = putStrLn (show x y)
This would mean that show should have a type Show a => a -> b -> String, but it has type show :: Show a => a -> String, hence the error.

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: Confused about type of `>>=` operator

I'm working my way through some introductory Haskell materials and am currently going through Monads. I conceptually understand that the >>= operator is of type:
(Monad m) => m a -> (a -> m b) -> m b.
In that context, I'm confused as to why the following code works, i.e., why it doesn't result in a type mismatch:
main = getLine >>= \xs -> putStrLn xs
Since we know that getLine :: IO String, I'd assume that it can be 'bound' with a function of type String -> IO String. However putStrLn is of a different type: putStrLn :: String -> IO ().
So why does Haskell allow us to use >>= with these two functions?
Let's just line up the types:
(>>=) :: m a -> ( a -> m b) -> m b
getLine :: IO String
putStrLn :: (String -> IO ())
Here we have m = IO, a = String, and b = (), so we can substitute these into >>='s type signature to get a final type signature of
(>>=) :: IO String -> (String -> IO ()) -> IO ()
() is a valid type (called unit, note that it contains only one possible non-bottom value) and in the definition would be b.
a = String and b = () thus we get:
IO String -> (String -> IO ()) -> IO ()
Since we know that getLine :: IO String, I'd assume that it can be 'bound' with a function of type String -> IO String.
Why would you think that? Look again at the type signature:
(>>=) :: m a -> (a -> m b) -> m b
Thing in the left is m a, thing on the right is m b. Most particularly the bit in the middle, a -> m b, says that the function you pass to >>= takes an a and returns an m b. It doesn't say it has to return m a, it says it can be m b, where b is any random type. It doesn't have to match a.
In your example, the lambda function takes a String and returns an IO (). So a = String and b = (). And that's fine.

Either [Char] a -> IO a function

How can I write a function so that Left x to an IO error but Right x returns its result as usual, i.e. the function has signature Either [Char] a -> IO a?
Basically I want the Left err result to become the err in the IO Monad.
One simple definition is:
f :: Either String a -> IO a
f = either (ioError . userError) return
Note that we can make this generic with fail, but it's really a historical accident that fail is in Monad to begin with, so I wouldn't use this definition:
f :: Monad m => Either String a -> m a
f = either fail return
A better generic version might use the MonadError class:
import Control.Monad.Error.Class
f :: MonadError e m => Either String a -> m a
f = either (throwError . strMsg) return

Resources