Proposal: Add &&& and *** to Data.Tuple

Jon Fairbairn jon.fairbairn at
Thu Oct 18 06:03:12 EDT 2007

"Josef Svenningsson" <josef.svenningsson at> writes:

> On 10/16/07, Ross Paterson <ross at> wrote:
>> On Mon, Oct 15, 2007 at 09:16:38PM +0200, Josef Svenningsson wrote:
>> > Despite the fact that we don't have a consensus I interpret the
>> > majority as a go for this patch.
>> In general, I think it's important to try for consensus with the core
>> libraries.  The discussion it requires is much more likely to explore
>> the issues.  Voting should be the last resort.
> That makes sense. What course of action do you suggest for this
> proposal then? I tried to continue the discussion with those who were
> against it in order to reach a consensus but I haven't gotten any
> replies.

Well, I wasn't sure what to say! 

Let me attempt to clarify my position: I dislike the
practice of having more than one name for the same thing
(and (***):: (Control.Arrow.Arrow a) => a b c -> a b' c' ->
a (b, b') (c, c') is, in this sense the same things as a
(***):: (b -> c) -> (b' -> c') -> (b, b') -> (c, c'))
because it increases the mental load without increasing
usefulness.  So if a specialised version of *** is
introduced, I'd want it to be called ***.

On top of that, I don't like having specialised versions
"get in the way" of general versions (by using up the name;
it may not matter too much for Data.Tuple, but it does
matter for map/fmap and others), hence my proposal of
"subsuming"; I'd prefer not to introduce specialised
versions of *** and &&& without such a mechanism.

At risk of reducing the chances of subsumption getting
developed into a workable idea, here's an alternative
suggestion (for the general issue, as much as for this
specific case): change the rules for the scope of names
imported and reexported. If module A imports a name from B
and re-exports it at a specialised type, and module C
imports both A and B, automatically resolve uses of that
name to the general version from B.  I don't like this idea
so much because it strikes me as ad-hoc, but it might work.

For this case, what I'm suggesting is that in Data.Tuple,
you'd have

   module Data.Tuple (***,&&&, ...) where
   import qualified Control.Arrow as C

   (***):: (b -> c) -> (b' -> c') -> (b, b') -> (c, c'))
   (***) = (Control.Arrow.***)

but if someone did this:

   module Example where
   import Control.Arrow
   import Data.Tuple

   f a b = a *** b

the new rules would mean that f got the type of

The only ill effect would be that the error messages might
be less helpful (and a user would always have the option of

   import Control.Arrow hiding ((***))

and getting the other behaviour), because the rules only
apply to re-export at a restricted type.

Jón Fairbairn                                 Jon.Fairbairn at

More information about the Libraries mailing list