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

class PairL p a where fst :: p->a                     -- May 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   -- roughly equivalent to PairL and PairR
  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)

-- ----------------------------------May--2003--L.A.-- CSSE--Monash--Uni--.au--

f2 = ( (\ch->if ch=='a' then 'z' else ch), (not) )  -- a Pair and a Function...


main = print "L.A., CSSE, Monash, 5/2003: type and class experiments"

 -- >> print( (fst (1,2))  :: Int )                        -- no instance...
 -- >> print( fst ((1,2) :: (Int,Int)) )                   -- no instance...
 >> print( fst ((1,2) :: (Int,Int)) :: Int )

 -- >> print( (\ch -> if ch=='a' then 'z' else ch) $ 'a')  -- no instance...
 >> print( (\ch -> if ch=='a' then 'z' else ch) $ 'a' :: Char )

-- f2 is both a Pair and
 >> print( (fst f2 :: Char -> Char) $ 'a' :: Char )        -- need the types!
-- also a Function
 >> print( (f2 $ ('a', False)) :: (Char,Bool) )            -- what a struggle
-- ----------------------------------------------------------------------------

--  "L.A., CSSE, Monash, 5/2003: type and class experiments"
--  1
--  'z'
--  'z'
--  ('z',True)
-- ----------------------------------------------------------------------------
