class Pair (or Tuple)?

There is a standard pair type (actually a tuple, (,)) in Haskell-98 but no class Pair built in. It is possible to define class Pair in standard Haskell-98, e.g.:

  module Main where               -- 2/2003
  import Prelude hiding(fst, snd) -- hide std ones

  class Pair p where              -- Pair
    fst :: (p a b) -> a
    snd :: (p a b) -> b

  instance Pair((,)) where        -- (,)
    fst (a,b) = a
    snd (a,b) = b
  ...

Type p is in class Pair if it has two type parameters, a and b, and operators fst and snd are defined on it.

However this class Pair cannot be combined naturally with class Function. We would like a Pair of Functions to be both a Pair and also a Function (of Pairs) in the "obvious" way, i.e. (f,g) $ (x,y) = (f$x, f$y).

  class (Pair pf, Function pf) => PairFunction pf where
  -- nix, i.e. subclass of Pair and also Function,
  -- but we can't make any instances of PairFunction !

The type-parameters cannot be made to match both Pair and also Function; we need something like pf ~ (a->c, b->d) and also pf ~ (a,b) -> (c,d) .

Multi-parameter classes

The non-standard type-extension, multi-parameter classes, does give a way around the problem above.

  module Main where           -- NB. ghc -fglasgow-exts
  import Prelude hiding(fst, snd, ($))  -- will redfine.

  class PairL p a where fst :: p->a         -- Feb 2003
  class PairR p b where snd :: p->b

  instance PairL (((,) a b)) a where
    fst (x,y) = x

  instance PairR (((,) a b)) b where
    snd (x,y) = y

  class Pair p a b where
    fst' :: p->a
    snd' :: p->b

  class Function fnType t u where
    ($) :: fnType -> t -> u

  instance Function (t->u) t u where f $ x = f x

  instance Function ((t->u),(v->w)) (t,v) (u,w) where
    (f, g) $ (x, y) = (f $ x, g $ y)
  ...

It is very slightly more convenient to use PairL and PairR in place of Pair but there is not much in it. (We could also consider class Triple, etc., and maybe class Tuple, one day.)

Now a Pair of Functions is both a Pair and also a Function (of Pairs). Using values from these classes, it is often necessary to give some extra type information to stop  ``no instance...''  errors, e.g.

  f2 = ( (\ch->if ch=='a' then 'z' else ch), (not) )
  ...
  print( (f2 $ ('a', False)) :: (Char,Bool) )  -- ***

which is a #@$! pity. Code [pair01.hs] (1.5K).