gust
gust

Reputation: 945

How to use value from different type monad in Haskell

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:

  1. In main, putStrLn is type IO Double but getDouble is type ThrowsError Double.

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

Answers (1)

luqui
luqui

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

Related Questions