- A+

Is there a way to write `do`

notation for a monad in a function which the return type isn't of said monad?

I have a main function doing most of the logic of the code, supplemented by another function which does some calculations for it in the middle. The supplementary function might fail, which is why it is returning a `Maybe`

value. I'm looking to use the `do`

notation for the returned values in the main function. Giving a generic example:

`-- does some computation to two Ints which might fail compute :: Int -> Int -> Maybe Int -- actual logic main :: Int -> Int -> Int main x y = do first <- compute x y second <- compute (x+2) (y+2) third <- compute (x+4) (y+4) -- does some Int calculation to first, second and third `

What I intend is for `first`

, `second`

, and `third`

to have the actual `Int`

values, taken out of the `Maybe`

context, but doing the way above makes Haskell complain about not being able to match types of `Maybe Int`

with `Int`

.

Is there a way to do this? Or am I heading towards the wrong direction?

Pardon me if some terminology is wrongly used, I'm new to Haskell and still trying to wrap my head around everything.

**EDIT**

`main`

has to return an `Int`

, without being wrapped in `Maybe`

, as there is another part of the code using the result of `main`

as `Int`

. The results of a single `compute`

might fail, but they should collectively pass (i.e. at least one would pass) in `main`

, and what I'm looking for is a way to use `do`

notation to take them out of `Maybe`

, do some simple `Int`

calculations to them (e.g. possibly treating any `Nothing`

returned as `0`

), and return the final value as just `Int`

.

Well the signature is in essence wrong. The result should be a `Maybe Int`

:

`main :: Int -> Int -> `**Maybe Int** main x y = do first <- compute x y second <- compute (x+2) (y+2) third <- compute (x+4) (y+4) **return** (first + second + third)

For example here we `return (first + second + third)`

, and the `return`

will wrap these in a `Just`

data constructor.

This is because your `do`

block, implicitly uses the `>>=`

of the `Monad Maybe`

, which is defined as:

`instance Monad Maybe where Nothing >>=_ = Nothing (Just x) >>= f = f x return = Just `

So that means that it will indeed "unpack" values out of a `Just`

data constructor, but in case a `Nothing`

comes out of it, then this means that the result of the entire `do`

block will be `Nothing`

.

This is more or less the convenience the `Monad Maybe`

offers: you can make computations as a chain of *succesful* actions, and in case one of these fails, the result will be `Nothing`

, otherwise it will be `Just result`

.

You can thus not at the end return an `Int`

instead of a `Maybe Int`

, since it is definitely possible - from the perspective of the types - that one or more computations *can* return a `Nothing`

.

You can however "post" process the result of the `do`

block, if you for example add a "default" value that will be used in case one of the computations is `Nothing`

, like:

`import Data.Maybe(fromMaybe) main :: Int -> Int -> `**Int** main x y = **fromMaybe 0** $ do first <- compute x y second <- compute (x+2) (y+2) third <- compute (x+4) (y+4) return (first + second + third)

Here in case the `do`

-block thus returns a `Nothing`

, we replace it with `0`

(you can of course add another value in the ** fromMaybe :: a -> Maybe a -> a** as a value in case the computation "fails").

If you want to return the first element in a list of `Maybe`

s that is `Just`

, then you can use ** asum :: (Foldable t, Alternative f) => t (f a) -> f a**, so then you can write your

`main`

like:`-- first `*non*-failing computation import Data.Foldable(asum) import Data.Maybe(fromMaybe) main :: Int -> Int -> Int main x y = fromMaybe 0 $ **asum** [ compute x y compute (x+2) (y+2) compute (x+4) (y+4) ]

Note that the `asum`

can still contain only `Nothing`

s, so you still need to do some post-processing.