8

From the docs:

(>>) : Sequentially compose two actions, discarding any value produced by the first

(*>) : Sequence actions, discarding the value of the first argument.

Both seem to me doing the same job.

duplode
  • 33,731
  • 7
  • 79
  • 150
  • One thing to watch out for: default implementations. By default, `m >> n = m >>= const n` and `m *> n = liftA2 (flip const) m n`. For many monads, these have quite different performance characteristics! In these cases, you should be sure to explicitly define the one(s) that would perform badly by default. – dfeuer Apr 01 '21 at 21:43

1 Answers1

10

They are equivalent, in practice.

Historically, Haskell did not have an Applicative typeclass (hence no *>), but only a Monad typeclass (with >>).

At a certain point, Applicative was made a superclass of Monad. At that point, it was introduced *> as a slightly more general variant of >>, which does not require one to work with a monad, but merely with an applicative functor.

(*>) :: Applicative f => f a -> f b -> f b
(>>) :: Monad f       => f a -> f b -> f b

The net result is that when working with applicatives, we can only use *>, while when working with monads (which are also applicatives) we can use either *> or >> interchangeably, since they are required to be equivalent in that case.

Several other monad-related functions have been similarly generalized to applicatives:

  • return is generalized by pure
  • ap is generalized by <*>
  • mapM is generalized by traverse
chi
  • 111,837
  • 3
  • 133
  • 218
  • "required" (or is it just "strongly encouraged"?) to be equivalent *semantically*, but there could be an operational difference, like `*>` being allowed to do its thing in parallel maybe? – Will Ness Mar 31 '21 at 09:47
  • @WillNess Sure, there might be some performance difference. The monad and applicative laws only require the semantics to be the same, as usual. Still, it would be very weird if they were implemented differently, with a significant performance difference, for the same monad. If one implementation is more performant, one would expect the other one to be replaced. – chi Mar 31 '21 at 10:10
  • hmm... so does this mean that `>>` is allowed to run the effects in parallel (if that makes sense for the particular type)? – Will Ness Mar 31 '21 at 10:19
  • @WillNess Only if that's still semantically equivalent. For `IO`, it is not, for instance. – chi Mar 31 '21 at 10:20
  • I was thinking about some kind of say eventual consistency... – Will Ness Mar 31 '21 at 10:24
  • @WillNess It might be the case. But even then, the same applies to `*>` too. I mean, you could make `>>` be sequential and `*>` be parallel (or vice versa) if one can't observe the difference from outside (except for performance), but ... why? – chi Mar 31 '21 at 10:30
  • 1
    no, I got that point. it's one and the same type after all, right. it's just that we usually think of monad as the essence of sequentiality but actually, `>>` _is_ allowed to run in parallel, in theory, it turns out. – Will Ness Mar 31 '21 at 10:35
  • 4
    One small correction: the `*>` operator was part of `Applicative` before it became a superclass of `Monad` (see [base-4.7.0.0](https://hackage.haskell.org/package/base-4.7.0.0/docs/Control-Applicative.html)). So, the history is: (1) Haskell has `Monad` only with `>>`; (2) `Applicative` gets introduced with corresponding `*>` operator; (3) `Applicative` becomes superclass of `Monad`, after which they're equivalent in practice. – K. A. Buhr Apr 01 '21 at 13:47