You don't have to handle it everywhere explicitly. This is where Functor, Applicative, Alternative, Monoid and Monad are for. They will do the plumbing for you. Eventually you will unpack the values, but this is only necessary if you change environment.
Say we have a failing computation:
failComp = Nothing
and a couple of succeeding computations:
sucComp = Just 1
sucComp2 = Just 2
We can use the typeclasses to avoid explicit unpacking:
-- Monad result: Just 3
add = do
x <- sucComp2
y <- sucComp
return $ x + y
Applicative result: Just 3
-- the <#> should be the applicative operator.
addapp = (+) <$> sucComp <#> sucComp2
Say we have a failing computation: failComp = Nothing
and a couple of succeeding computations: sucComp = Just 1 sucComp2 = Just 2
We can use the typeclasses to avoid explicit unpacking:
-- Monad result: Just 3
add = do x <- sucComp2 y <- sucComp return $ x + y
Applicative result: Just 3
-- the <#> should be the applicative operator. addapp = (+) <$> sucComp <#> sucComp2
Alternative: result (Just 1)
val = failComp <|> sucComp
Monoid: result (Just 2)
mon = failComp <> sucComp2
Functor result (Just 6)
-- # should be multiply operator
func = fmap (#3) sucComp2