Tombert
Tombert

Reputation: 530

"Couldn't match type `Maybe' with `IO' Expected type: IO String Actual type: Maybe String" In Haskell

I am trying to wrap my head around Monads, and feel that if I could get an explaination to why this doesn't compile, I'd have a better understanding.

module Main where
import Data.Maybe
import System.Environment

myFunc :: String-> Maybe String
myFunc x = Just x

main :: IO ()
main = myFunc "yo" >>= putStrLn 

The error I get is

blah.hs:9:10:
    Couldn't match type `Maybe' with `IO'
    Expected type: IO String
      Actual type: Maybe String
    In the return type of a call of `myFunc'
    In the first argument of `(>>=)', namely `myFunc "yo"'
    In the expression: myFunc "yo" >>= putStrLn

I realize that the issue is that I'm trying to match a Maybe with an IO, but I'm not entire sure how to cast my Maybe'd variable into an IO. Any help would be greatly appreciated!

Upvotes: 2

Views: 4080

Answers (2)

Jonathan Cast
Jonathan Cast

Reputation: 4635

Casting Maybe String to IO is the same as turning a Maybe String to anything else: you need to pick a value to map Nothing to, and a value to map each Just x to. Since you want to map to IO String, I assume you want to map Nothing to an exception and Just x to return x:

import Control.Exception

data NoString = NoString deriving (Typeable, Show)
instance Exception NoString

maybeToIO :: Maybe String -> IO String
maybeToIO Nothing = throwIO NoString
maybeToIO (Just x) = return x

main = maybeToIO (myFunc "yo") >>= putStrLn

However, I suspect that, in a real application, you would want to map Nothing onto defined behavior; maybe printing nothing, for example:

main = case myFunc "yo" of
    Nothing -> return ()
    Just x -> putStrLn x

Basically, don't get too hung up on the fact that Maybe and IO are both monads; the monad operations are just ways of making values of those types; once you've got your Maybe values, you still need to process them as ordinary data structures (although Haskell does have awesome ways of doing that:

main = maybe (return ()) putStrLn $ myFun "yo"

for example).

Upvotes: 3

Sibi
Sibi

Reputation: 48644

You are correct in realizing that you are trying to match a Maybe with an IO. For the bind (>>=) operator to typecheck, both the Monad should be the same. One way to solve this problem would be to wrap the Maybe in an IO monad using return:

return (myFunc "yo") >>= putStrLn . show

Or more simply:

return (myFunc "yo") >>= print

That being said, you don't need all the fancy monad operators here. This should simply work:

main :: IO ()
main = print . myFunc $ "yo"

Upvotes: 8

Related Questions