4

Yesterday I read up some on the whole monad thing. I by no means grasp it, but it will not stop me from trying to use it. Some of the answers in this question really do push that monads is there to make things nicer, and more readable. 'Haskell has nice support for monads', does that mean that I can write nice code with for example maybe out of the box?

Or does it mean that I can write code for the maybe type which makes it easy to use.

I encountered the following problem when doing advent of code:

Add 1 to the values in two Maybes and then multiply them together.

After reading question on multiplying two maybes and also checking out typeclassopedia I arrived at (after some serious head scratching):

let test = Just (*) <*> ((+1) <$> marker1Pos) <*> ((+1) <$> marker2Pos)

It works, but to me that looks less than ideal.

Can I do it with a do-block which I read about in the first link?

Adam
  • 2,845
  • 2
  • 32
  • 46
  • This looks cleaner to me: `getAp ((Ap marker1Pos + 1) * (Ap marker2Pos + 1))`. It uses a `newtype` that introduces numeric syntax for anything that's already a monad (and some stuff that isn't ;-). – Daniel Wagner Dec 14 '22 at 20:11
  • Note that this doesn't require the `Monad` instance for `Maybe`, only its `Applicative` instance. – chepner Dec 14 '22 at 20:21

2 Answers2

10

Sure, you can do it with a do.

do  x <- marker1Pos
    y <- marker2Pos
    return ((x + 1) * (y + 1))

I would also tend to use liftM2 or liftA2 for the version you wrote, and I'd also tend to use fmap instead of <$> for sections. You may or may not find this more appealing, but I offer it in case you do:

liftA2 (*) (fmap (+1) marker1Pos) (fmap (+1) marker2Pos)
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
4

You can work with on :: (b -> b -> c) -> (a -> b) -> a -> a -> c here:

import Control.Applicative(liftA2)
import Data.Function(on)

f :: (Applicative f, Num a) => f a -> f a -> f a   
f = liftA2 (*) `on` fmap (1+)
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Yyyeah... but this is a bit dubious. If we're going to factor out the "apply +1 to all", then we should probably right away do it on a _list_, i.e. `traverse product . map (fmap (+1))`. – leftaroundabout Dec 14 '22 at 19:18