1

This is a wrapper to a couple of two objects of the same type

data Pair a = Pair a a deriving (Show)
--newtype Pair a = Pair (a,a) deriving (Show) -- not this

It seems to be easily made a functor, by having the mapping function act on both values,

instance Functor Pair where
  fmap f (Pair a b) = Pair (f a) (f b)

and the functor laws seem to hold too, am I wrong? Ok, this instance seems pretty useless, but at least it looks intuitive to me: what else would I want to do, given a function and a wrapper to two values, instead of doing this?

We can also make it an applicative functor

instance Applicative Pair where
  pure a = Pair a a
  Pair f g <*> Pair x y =  Pair (f x) (g y)

even though I've not checked if composition and interchange laws are verified (identity and homomorphism are). Like before, I see this instance a bit trivial but easy to look at: what else would I do, instead of this?

However, I don't see how it can be made a Monad. (>>=)'s second arument should be a function which acts on one entity of the type given to the Monad type constructor, right? In this case, however, Pair contains two, possibly different, values. So there's a problem of choosing how a function, say, of type Int -> Pair Int should act on the inside of, say, Pair 3 4. I guess I could invented it, but having it adhere to the monad laws does not seem obvious to me. Plus it should be consistent with the above Functor and Applicative instances.

Is there an obvious reason why Pair cannot be made a monad? Or maybe it can, and I'm just confused?

Enlico
  • 23,259
  • 6
  • 48
  • 102
  • 2
    I can't answer your question firmly either way, but note this is essentially a `ZipList` limited to 2 elements, and `ZipList` is well known for being an `Applicative` but not a `Monad`. (Although I've never seen a proof that it can't be a Monad.) – Robin Zigmond Oct 06 '20 at 06:26
  • The key is to recognize that `>>=` has to do some additional work before returning a new `Pair`. `(Pair x y) >>= f`, as intermediate values, produces *two* pairs, one (`f x == Pair x' y'`) based on `x` and one (`f y == Pair x'' y''`) on `y`. `>>=` then has to merge them, and the only law-abiding way to do that is to produce `Pair x'' y''`, rather than one of the other three options. – chepner Oct 06 '20 at 12:34
  • 2
    Your homogeneous `Pair` is isomoprhic to `(->) Bool`, which is a monad. This generalizes to tuples. – chi Oct 06 '20 at 13:00
  • 2
    @chepner, I think you mean `Pair x' y''`. – dfeuer Oct 06 '20 at 20:04
  • @chepner, why is that? It seems that what you say underlies an asymmetry between `Pair`'s arguments. – Enlico Oct 06 '20 at 20:10
  • @dfeuer, then why not `Pair x'' y'`? – Enlico Oct 06 '20 at 20:10
  • @chi, are you then saying that `Pair` can be a monad? If so, how? Maybe someone could vote to reopen the question? – Enlico Oct 06 '20 at 20:11
  • 1
    This question as posed is really a duplicate of the other one. You should ask a new question about why the instance Aadit M. Shah gives is unique. I would be very interested in whether the answer relies essentially on parametricity. – dfeuer Oct 06 '20 at 20:36
  • 1
    @Enrico See https://stackoverflow.com/a/58753984/1126841. You need `Pair x' y''` (as dfeuer corrected my typo) to ensure that your definition of `>>=` obeys the monad laws. – chepner Oct 06 '20 at 20:42
  • 1
    @Enrico Convert a `Pair a` to a `Bool -> a` in the obvious way. Use the standard `(->) Bool` monad definition. Convert any resulting `(->) Bool t` back to `Pair t`. I mean, once you understand it's isomorphic to something (`Bool -> a`) which we already know it's a monad, it's just a matter of copying the same instance and apply the isomorphism so to adapt the instance to the new type (`Pair a`). You can try doing this as a nice exercise. – chi Oct 06 '20 at 21:30
  • @chi, ok, I'll try to "parse" your comment in the weekend. I'm still quite _ignorant_ about morphisms and category theory in general. – Enlico Oct 06 '20 at 21:33
  • 1
    Any homogeneous pair `p` can be converted to a function from bool i.e. `\b -> if b then fst p else snd p`. Vice versa, any such function `f` can be concerted to an homogeneous pair `(f True, f False)`. Further, these conversions simplify (they are inverses). So, once you know how to handle `Bool -> ...` as a monad, just apply the conversions as needed (possibly in both directions) to the same instance. It's not obvious at first, but it can be a great learning exercise. – chi Oct 06 '20 at 22:07
  • Oh, ok, I see. In other words `Bool -> a` and `(a,a)` are isomorphic because they are both ways of representing only two results/values. As regards _how_ `(a,a)` can be a `Monad`, I'll refer to the linked answer to understand why `>>=` has to be like that, and, if something is not clear to me, I'll ask a separate question to address it and link it off a comment here (or I'll simply modify this to get it reopened). – Enlico Oct 10 '20 at 11:08

0 Answers0