maxloo
maxloo

Reputation: 491

haskell *> sequencing operator

I have a question arising from the answer to my question at: haskell Either and Validation Applicative

My code is posted there.

It concerns the use of the *> sequencing operator instead of the <*> applicative operator.

Based on the explanation at https://hackage.haskell.org/package/base-4.15.0.0/docs/Control-Applicative.html#v:-42--62-, I understand that *> sequences actions, discarding the value of the first argument. So for my code, I've tried fail6 = fail2 *> success, which works, but it's not supposed to work because the value of the first argument, namely fail2, should be discarded. Why does fail6 work?

The output of fail6 is Failure [MooglesChewedWires,StackOverflow].

Upvotes: 1

Views: 388

Answers (2)

dfeuer
dfeuer

Reputation: 48591

"Result" is quite a vague term, isn't it? When we talk about Functor, Applicative and Monad, we tend to refer to zero or more values in some sort of "context". So

  • IO a: an I/O computation producing a value of type a.
  • [a]: a list of zero or more values of type a.
  • Maybe a: zero or one elements of type a.
  • Either e a: just like Maybe a except that the no as case is "decorated" with something of type e.
  • (x, a): a value of type a "decorated" with one of type x.
  • Identity a: a value of type a without any context.

When you "discard the result", that means that you care about the context but not about the value. So:

  • What did the I/O do?
  • How many elements does the list have?
  • Was the value Just something or Nothing?
  • Was the value Right something or Left e?
  • What was the decoration?
  • No information.

Upvotes: 3

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476624

With "discard the result", it means the result of an applicative. So for an Either that means a Right y. (*>) is thus equivalent to:

(*>) :: Applicative f => f a -> f b -> f b
(*>) f g = liftA2 (const id) f g

or in another form:

(*>) :: Applicative f => f a -> f b -> f b
(*>) f g = (const id) <$> f <*> g

It thus runs the two actions and returns the second result, but this in the "Applicative context".

For example for an Either, this is implemented as:

instance Applicative (Either a) where
    pure = Right
    Left e <*> _ = Left e
    _ <*> Left e = Left e
    Right f <*> Right x = Right (f x)

This thus means that (*>) is implemented for an Either as:

-- (*>) for Either
(*>) :: Either a b -> Either a c -> Either a c
Left x *> _ = Left x
_ *> Left x = Left x
Right _ *> Right x = Right x

or equivalent:

-- (*>) for Either
(*>) :: Either a b -> Either a c -> Either a c
Left x *> _ = Left x
_ *> x = x

If the first operand is thus a Right …, it will return the second operand, if the first operand is Left x, it will return Left x.

Upvotes: 4

Related Questions