Reputation: 945
Honestly, I feel like this must have a dupe somewhere, but I couldn't find it even after searching .
Say I have the following code to simply get read a double from the user and echo it back:
import qualified Control.Monad.Except as E
import Text.Read(readMaybe)
data Error = ParseError String
| Default String deriving (Show)
type ThrowsError = Either Error
main = do
putStrLn "Enter your number: "
val <- getDouble
print val
parseString :: String -> ThrowsError Double
parseString val = maybe (E.throwError $ ParseError val) return
(readMaybe val :: Maybe Double)
getDouble :: ThrowsError Double
getDouble = getLine >>= parseString
This breaks in two places:
In main
, putStrLn
is type IO Double
but getDouble
is type ThrowsError Double
.
In getDouble
, getLine
is type IO Double
but parseString
returns IO Double
.
Essentially, I'd want to be able to extract the value out of the IO
monad, apply computations on it, and put it back inside the appropriate monad. However, the bind function seems to expect the same monad types for input and output, so what I want to do doesn't work.
What's the way around it?
Upvotes: 2
Views: 374
Reputation: 60543
You don't need any transformers. parseString
is a pure function, so to apply it to a monadic action you use fmap
(aka (<$>)
), not (>>=)
as you have.
getDouble :: IO (ThrowsError Double)
getDouble = parseString <$> getLine
You would use (>>=)
if parseString
returned an IO something
.
Upvotes: 9