{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleInstances, FlexibleContexts #-} module Types where import Prelude hiding (lookup) import Control.Monad ((>=>)) -- Code from the exam question: class GMapKey k where data GMap k :: * -> * empty :: GMap k v lookup :: k -> GMap k v -> Maybe v insert :: k -> v -> GMap k v -> GMap k v instance GMapKey () where data GMap () v = GMU (Maybe v) empty = GMU Nothing lookup () (GMU mv) = mv insert () v (GMU _) = GMU $ Just v instance (GMapKey a, GMapKey b) => GMapKey (Either a b) where data GMap (Either a b) v = GME (GMap a v) (GMap b v) empty = GME empty empty lookup (Left a) (GME gm1 _gm2) = lookup a gm1 lookup (Right b) (GME _gm1 gm2 ) = lookup b gm2 insert (Left a) v (GME gm1 gm2) = GME (insert a v gm1) gm2 insert (Right a) v (GME gm1 gm2) = GME gm1 (insert a v gm2) instance (GMapKey a, GMapKey b) => GMapKey (a, b) where data GMap (a, b) v = GMP (GMap a (GMap b v)) empty = GMP empty lookup (a, b) (GMP gm) = lookupGMP a b gm -- TODO insert (a, b) v (GMP gm) = GMP (insertGMP a b v gm) -- TODO {- Part 3 (a): Fully expand the type family application |GMap (Either () (Bit, a)) v|. You may ignore the constructors |GMU|, |GME| and |GMP| as I did in the comment after type signature for |t0|. ---- GMap (Either () (Bit, a)) v ~= {- instance for Either -} (GMap () v, GMap (Bit, a) v) ~= {- instances for () and (,) -} (Maybe v, GMap Bit (GMap a v)) ~= {- expand type synonym Bit -} (Maybe v, GMap (Either () ()) (GMap a v)) ~= {- instance for Either -} (Maybe v, (GMap () (GMap a v), (GMap () (GMap a v)))) ~= {- instance for (), twice -} (Maybe v, (Maybe (GMap a v), Maybe (GMap a v))) -} -- ---------------- {- Task 3 (b): Give the type signatures for and implement |lookupGMP| and |insertGMP|. -} lookupGMP :: (GMapKey a, GMapKey b) => a -> b -> GMap a (GMap b v) -> Maybe v lookupGMP a b = lookup a >=> lookup b insertGMP :: (GMapKey a, GMapKey b) => a -> b -> v -> GMap a (GMap b v) -> GMap a (GMap b v) insertGMP a b v gm = insert a (insert b v innermap) gm where innermap = lookupDef empty a gm lookupDef :: GMapKey k => v -> k -> GMap k v -> v lookupDef def k = maybe def id . lookup k -- ---------------------------------------------------------------- {- Task 3 (c): Give type signatures for and implement |fmapGMU|, |fmapGME| and |fmapGMP|. -} -- Code from the exam question: instance Functor (GMap ()) where fmap = fmapGMU instance (Functor (GMap a), Functor (GMap b)) => Functor (GMap (Either a b)) where fmap = fmapGME instance (Functor (GMap a), Functor (GMap b)) => Functor (GMap (a, b)) where fmap = fmapGMP -- Answer: fmapGMU :: (a->b) -> GMap () a -> GMap () b fmapGMU f (GMU ma) = GMU $ fmap f ma -- the inner fmap is for Maybe fmapGME :: (Functor (GMap c), Functor (GMap d)) => (a->b) -> GMap (Either c d) a -> GMap (Either c d) b fmapGME f (GME gma gmb) = GME (fmap f gma) (fmap f gmb) fmapGMP :: (Functor (GMap c), Functor (GMap d)) => (a->b) -> GMap (c, d) a -> GMap (c, d) b fmapGMP f (GMP gmab) = GMP $ fmap (fmap f) gmab