Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monads in Haskell

Tags:

haskell

monads

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)))
like image 486
hask1023 Avatar asked Jul 15 '26 23:07

hask1023


2 Answers

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)
like image 104
Iceland_jack Avatar answered Jul 18 '26 13:07

Iceland_jack


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 (+)
like image 20
Willem Van Onsem Avatar answered Jul 18 '26 12:07

Willem Van Onsem