I'm new to Monads and was trying to write an add function and I'm unsure why this doesn't work. When using monads, is there a specific way you need to return a value?
monadd :: (Monad m, Num b) => m b -> m b -> m b
monadd mx my = mx >>= (\x -> my >>= (\y -> (x + y)))
You want to use pure (more general form of return)
monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = mx >>= (\x -> my >>= (\y -> pure (x + y)))
The right-hand side (continuation) of >>= must always return a monadic action. But when you add x + y :: a you have a number. You need pure (x + y) :: m a to turn it into a monadic action:
monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = mx >>= (\x -> my >>= (\y -> pure (x + y)))
^^^ ^ ^^^ ^ ^^^^^^^^^^^^
m a a m a a m a
You can equivalently write it in do-notation
monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = do
x <- mx
y <- my
pure (x + y)
Actually. This doesn't require Monad. Applicative (n-ary lifting) is sufficient:
monadd :: Applicative m => Num a => m a -> m a -> m a
monadd = liftA2 (+)
Reminder that Functor lifts a unary function and Applicative lifts constants and n-ary functions (where liftA0 = pure and liftF1 = fmap):
liftA0 :: Applicative f => (a) -> (f a)
liftF1 :: Functor f => (a -> b) -> (f a -> f b)
liftA2 :: Applicative f => (a -> b -> c) -> (f a -> f b -> f c)
liftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d)
You only need Monad when there is a dependency between the computations. Notice that in your case the my computation does not dependent on the result of the mx computation.
If m b depended on the output of m a it would become a -> m b. Then Monad is required:
dependency :: Monad m => (a -> b -> c) -> m a -> (a -> m b) -> m c
dependency (·) as bs = do
a <- as
b <- bs a
pure (a · b)
When using monads, is there a specific way you need to Return a value?
Yes, you will need to wrap x and y back in a monadic context, with return :: Monad m => a -> m a, so:
monadd :: (Monad m, Num b) => m b -> m b -> m b
monadd mx my = mx >>= (\x -> my >>= return (x+y)))
Since the two operations of the monad mx and my operate independently of each other however, Applicative is sufficient, you can implement this as:
monadd :: (Applicative f, Num b) => f b -> f b -> f b
monadd mx my = (+) <$> mx <*> my
or through liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c:
monadd :: (Applicative f, Num b) => f b -> f b -> f b
monadd = liftA2 (+)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With