6
votes

Suppose I have a value of type Monad m => (m a, m a), and I want to "sequence" the pair to create a value of type Monad m => m (a, a) that combines the monadic context of the two values in the same way the "sequence" function does. Is there some standard function or standard way of doing this? And does this operation even make sense?

3
I suppose the most natural approach would be sequence' (ma,mb) = (x,y) where x = head l y = last l l = sequence [ma, mb], just treating the tuple as a list of length 2? - C. Quilley
@C.Quilley Use backticks to include inline code in comments `some code`. Also, it's much easier if you use the ; to separate definitions: sequence' (ma, mb) = (x, y) where x=head L; y= last L; L = sequence [ma, mb] - Bakuriu
uncurry $ liftM2 (,) :: Monad m => (m a1, m a2) -> m (a1, a2) You can also do it with applicatives. I wonder if there are mono-traversable instances for homogenous tuples up to some size. - Boyd Stephen Smith Jr.
I would say two things. First: this is strikes me as being simple and uncommon enough that there wouldn't be a library function for it; you can just do it online as Boyd suggests. Second: if such a function were to exist, you'd want to file it under Applicative, and it'd be something like (<,>) :: Applicative f -> f a -> f b -> f (a, b). This function is not a standard one, but you often find people talking about it because the associativity law that Applicative instances must obey is basically a <,> (b <,> c) == (a <,> b) <,> c (up to isomorphism). - Luis Casillas

3 Answers

10
votes
ghci> import Control.Lens
ghci> sequenceOf both (getLine, getLine)
Apples
Bananas
("Apples","Bananas")
8
votes

There wouldn't be a single function for all the different tuple types, since it wouldn't have a single type.

You could define a family of functions like:

ts0 = return
ts2 = uncurry $ liftM2 (,)
ts3 = uncurr3 $ liftM3 (,,)
{- ... -}
uncurr3 f (x, y, z) = f x y z

Of course, sequence in general is better applied to applicatives instead of monads, which is why it is part of the Traversable typeclass. It would be possible to make homogenous tuples [(a,a,a) but not (a,b,a)] an instance of MonoTraversable, I believe.

You should also see another answer which indicates there is already a library containing this family of functions.

7
votes

The tuple package has Data.Tuple.Sequence.sequenceT which is overloaded for up to 15-tuples.