MRE:
foo :: (Eq a) => a -> [a] -> Maybe Int
foo _ [] = Nothing
foo n (m:ms)
| -- some conditional statements that return Just <number here>
| otherwise = 3 + (foo n ms)
Error:
Could not deduce (Num (Maybe Int)) arising from a use of ‘+’
from the context: Eq a
bound by the type signature for:
foo :: forall a. Eq a => a -> [a] -> Maybe Int
at functions.hs:22:1-40
In the expression: 3 + (foo n ms)
What works:
otherwise = fmap (+3) (foo n ms)
Is there any way to do this without fmap?
PS: The only constraint on a is Eq
has to hold.
3
The problem is that 3
is Int
but (foo n ms)
is Maybe Int
, and you cannot add them.
You can pattern match on the result of foo n ms
explicitly if you don’t want to fmap
over Maybe Int
.
otherwise = case foo n ms of
Just x -> Just (3 + x)
Nothing -> Nothing
It’s also an option to use a Monad
instance of Maybe
, but it’s kind of a redundant version of fmap (+3) (foo n ms)
.
otherwise = do
x <- foo n ms
pure (3 + x)
Yet another option would be lifting (+)
to Maybe Int -> Maybe Int -> Maybe Int
with liftA2
, but again, it’s kind of another redundant version.
otherwise = liftA2 (+) (Just 3) (foo n ms)
Is there any way to do this without fmap?
You can use an accumulator, which is often more useful:
foo :: (Eq a) => a -> [a] -> Maybe Int
foo n xs = go xs n 0 where
go [] _ _ = Nothing
go (m:ms) n a = go ms n (a+3)
We thus start with a zero as third parameter, and sum up 3
each time the go (m:ms) n a
fires.
This will avoid wrapping and unwrapping the value into a Just
data constructor. At the end you thus use a Just a
(or you add a
to the result). So you thus do some additional bookkeeping with the recursion.
Any applicative can be given a Num
instance; see also Ap
. Some variations:
-- reuse the existing instance (problem: orphan instance)
deriving instance Num a => Num (Maybe a) via Ap Maybe a
-- implement the instance yourself (still an orphan)
instance Num a => Num (Maybe a) where
fromInteger = pure . fromInteger
(+) = liftA2 (+)
abs = fmap abs
-- ...etc.
-- use Ap in your function definition
foo :: Eq a => a -> [a] -> Ap Maybe Int
foo _ [] = Ap Nothing
foo n (m:ms)
| ...
| otherwise = 3 + foo n ms
-- use Ap as an internal implementation detail
foo :: Eq a => a -> [a] -> Maybe Int
foo n_ ms_ = getAp (foo' n_ ms_) where
foo' _ [] = Ap Nothing
foo' n (m:ms)
| ...
| otherwise = 3 + foo n ms
-- realize that all the fanciness is not worth avoiding one fmap
foo :: Eq a => a -> [a] -> Maybe Int
foo _ [] = Nothing
foo n (m:ms)
| ...
| otherwise = (3+) <$> foo n ms
Be aware, though, that there’s one law that most Num
instances have that Ap Maybe a
violates: Ap Nothing - Ap Nothing /= 0
.
2
Consider whether you need arithmetic with Nothing
, or if that’s just a one-time issue for empty lists. That is, can you structure your code something like the following?
foo :: Num a => a -> [a] -> Maybe a
foo _ [] = Nothing
foo n ms = foo' n ms where
foo' :: Num a => a -> [a] -> a
foo' n [] = ...
foo' n (m':ms') = 3 + foo' n ms'