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)))
CodePudding user response:
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 monads 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 ( )
CodePudding user response:
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 be 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)