1

I am sure many of you have seen code like this:

someFunc :: MaybeT IO ()
someFunc = do
    foo1 <- MaybeT $ ...
    foo2 <- MaybeT . return $ ...
    foo3 <- lift $ ...
    foo4 <- liftIO $ ...
    ...

I am talking about those MaybeT, MaybeT . return, lift, liftIO, etc.

This type of noise clutters up my MaybeT code.

I have the feeling there is a better way. Is there?

haskellHQ
  • 1,027
  • 6
  • 15
  • Could you add a complete example? This is hard to answer without seeing the right hand sides. – Lee Nov 16 '16 at 20:27
  • This sort of problem is generally solved by using `mtl`. In your case, because you are using `MaybeT`, it is not as obvious how to do this. Slightly confusingly, the `MonadMaybe` constraint one might want is just `MonadPlus` (see [this pull request](https://github.com/ekmett/mtl/issues/6)). This would be easier to answer if your example was more complete (ie compileable). – Alec Nov 16 '16 at 20:27

1 Answers1

2
someFunc :: MaybeT IO ()

To be consistent with the advice below, rewrite someFunc :: (Alternative m, MonadIO m) => m (). This is not needed for implementing someFunc, but is needed for using someFunc in other operations without explicit lifting when the other operations are not specifically in the MaybeT IO monad.

someFunc = do
    foo1 <- MaybeT $ ...

Rewrite ... to use return and empty instead of return . Just and return Nothing.

    foo2 <- MaybeT . return $ ...

Rewrite ... to use return and empty instead of Just and Nothing.

    foo3 <- lift $ ...

For MaybeT IO, the lift and liftIO operations are identical, so see the next suggestion. In the general case (rather than specific to MaybeT IO), rewrite ... to be typeclass polymorphic for a class that your concrete monad inhabits.

    foo4 <- liftIO $ ...

Can't do much about this. Sometimes it is possible to give ... a MonadIO constraint rather than an IO type. Usually that just shifts the location of the liftIO, though; it has to appear somewhere.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • Clearly `Alternative` and `MonadPlus` are identical here. Are there conventions on when to use which as constraints? (I've read [this excellent answer by Edward Kmett](http://stackoverflow.com/questions/10167879/distinction-between-typeclasses-monadplus-alternative-and-monoid)). – Alec Nov 16 '16 at 21:27
  • 1
    @Alec If you can give your operation an `Alternative`-polymorphic type, you probably should: as noted there, `MonadPlus` is a stronger claim, hence has fewer instances, is "less polymorphic" in a sense, and can not be used at as many different types by the caller. On the other hand, sometimes something you write assumes one of the `MonadPlus` laws, in which case you have no choice but to upgrade from `Alternative` to `MonadPlus`. – Daniel Wagner Nov 16 '16 at 21:44