Home > Software engineering >  Monads in Haskell
Monads in Haskell

Time:12-05

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)
  • Related