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