Search code examples
haskellmonadsmonad-transformers

Using MaybeT with `join`


Looking at the MaybeT transformer:

ghci> let x = MaybeT $ Just 1234
ghci> let y = runMaybeT x
ghci> :t y
y :: Num (Maybe a) => Maybe (Maybe a)

Now I want to get the inner Maybe a, but join does not work.

ghci> join y

<interactive>:53:1:
    No instance for (Num (Maybe a0)) arising from a use of `it'
    In a stmt of an interactive GHCi command: print it

How can I get at the inner Maybe a value?


Solution

  • You are not using the MaybeT constructor correctly. Look at the type signatures:

    MaybeT    ::            m   (Maybe a) -> MaybeT m a
                            |   |       |
                          /-+-\ \---+---/
                          |   |     |
    Just 1234 :: Num x => Maybe     x
    

    Hence:

    m := Maybe
    x := Maybe a
    

    Therefore:

    MaybeT $ Just 1234 :: Num (Maybe a) => MaybeT Maybe a
    

    So here Maybe a is expected to be an instance of Num which is clearly wrong. An option type is not a number. Why does this problem arise?

    Consider the numeric literal 1234. Numeric literals are bounded polymorphic values in Haskell. Hence, they have the type Num x => x. In other words 1234 can be of any type depending upon the context as long as that type is an instance of Num (e.g. Int, Integer, Double).

    In your code, the polymorphic type x is instantiated to Maybe a which is why Haskell expects Maybe a to be an instance of Num.

    I think what you really want to do is this:

    MaybeT             ::                     m (Maybe a) -> MaybeT m a
    
    return $ Just 1234 :: (Num a, Monad m) => m (Maybe a)
    

    Therefore:

    MaybeT $ return $ Just 1234 :: (Num a, Monad m) => MaybeT m a
    

    Now you can easily extract the inner Maybe a:

    runMaybeT $ MaybeT $ return $ Just 1234 :: (Num a, Monad m) => m (Maybe a)
    

    Since the inner Maybe a value is wrapped in a monad all you need to do is use >>= to extract the Maybe a:

    (runMaybeT $ MaybeT $ return $ Just 1234) >>= \x -> do
        -- do something with x
        -- x :: Maybe a
    

    You could also write this using the do notation:

    do
        x <- runMaybeT $ MaybeT $ return $ Just 1234
        -- do something with x
        -- x :: Maybe a
    

    Hope that helps.