instance (Semigroup a) => Applicative (These a) where
pure = That
This a <*> _ = This a
That _ <*> This b = This b
That f <*> That x = That (f x)
That f <*> These b x = These b (f x)
These a _ <*> This b = This (a <> b)
These a f <*> That x = These a (f x)
These a f <*> These b x = These (a <> b) (f x)
When one of the These is a This, the result is always This. However, there appears to be an assymetry when one of the These is a These constructor. The information from the These constructor is either preserved in the result or discarded, depending on which one is the argument.
This a <*> _ = This a
These a _ <*> This b = This (a <> b)
Testing this in ghci:
ghci> This "a" <*> These "b" True
This "a"
ghci> These "a" not <*> This "b"
This "ab"
What would the consequence be if we added a case like
This a <*> These b _ = This (a <> b)
to the Applicative instance? Would this break the Applicative laws?
Adding the case This a <*> These b _ = This (a <> b) to the Applicative instance of These would not break the Applicative laws.
The Applicative laws state that the pure function should behave as an identity under (<*>) and that (<*>) should be associative. Let’s analyze these laws with the newly added case:
Identity Law: pure id <*> v = v
When v is This x, the result would be This x since This x is always returned when This is the first argument in the existing implementation.
When v is That y, These y z, or These y z, the result would be the same as before since the existing cases already handle these scenarios correctly.
Hence, the identity law would still hold.
Associative Law: u <*> (v <*> w) = (pure (.) <*> u <*> v) <*> w
When u is This x, v is This y, and w is This z, the result would be This (x <> (y <> z)) in both cases, since (x <> (y <> z)) is the same as ((x <> y) <> z).
When u is This x, v is This y, and w is That z or These z w, the result would be This (x <> y) in both cases, since (x <> y) is the same as ((x <> y) <> z).
This is consistent with the existing behavior of the other cases, so the associative law would still hold.
Therefore, adding the case This a <*> These b _ = This (a <> b) would not break the Applicative laws.