emgm-0.3: src/Generics/EMGM/Functions/Map.hs
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
-----------------------------------------------------------------------------
-- |
-- Module : Generics.EMGM.Functions.Map
-- Copyright : (c) 2008, 2009 Universiteit Utrecht
-- License : BSD3
--
-- Maintainer : generics@haskell.org
-- Stability : experimental
-- Portability : non-portable
--
-- Summary: Generic functions that translate values of one type into values of
-- another.
--
-- 'map' is a generic version of the @Prelude@ @map@ function. It works
-- on all supported container datatypes of kind @* -> *@. The 'map' function is
-- equivalent to 'fmap' after @deriving 'Functor'@ if that were possible.
--
-- 'cast' is a generic and configurable function for converting a value of one
-- type into a value of another using instances provided by the programmer.
-----------------------------------------------------------------------------
module Generics.EMGM.Functions.Map (
Map(..),
map,
replace,
bimap,
cast,
) where
import Prelude hiding (map)
import Generics.EMGM.Common
-----------------------------------------------------------------------------
-- Types
-----------------------------------------------------------------------------
-- | The type of a generic function that takes a value of one type and returns a
-- value of a different type.
newtype Map a b = Map { selMap :: a -> b }
-----------------------------------------------------------------------------
-- Generic2 instance declaration
-----------------------------------------------------------------------------
rconstantMap :: a -> a
rconstantMap = id
rsumMap :: Map a1 a2 -> Map b1 b2 -> a1 :+: b1 -> a2 :+: b2
rsumMap ra _ (L a) = L (selMap ra a)
rsumMap _ rb (R b) = R (selMap rb b)
rprodMap :: Map a1 a2 -> Map b1 b2 -> a1 :*: b1 -> a2 :*: b2
rprodMap ra rb (a :*: b) = selMap ra a :*: selMap rb b
rtypeMap :: EP b r -> EP d a -> Map r a -> b -> d
rtypeMap ep1 ep2 ra = to ep2 . selMap ra . from ep1
instance Generic2 Map where
rconstant2 = Map rconstantMap
rsum2 ra rb = Map (rsumMap ra rb)
rprod2 ra rb = Map (rprodMap ra rb)
rtype2 ep1 ep2 ra = Map (rtypeMap ep1 ep2 ra)
-----------------------------------------------------------------------------
-- Exported functions
-----------------------------------------------------------------------------
-- | Apply a function to all elements of a container datatype (kind @* -> *@).
map :: (FRep2 Map f) => (a -> b) -> f a -> f b
map = selMap . frep2 . Map
-- | Replace all @a@-values in @as@ with @b@. This is a convenience function for
-- the implementation @'map' ('const' b) as@.
replace :: (FRep2 Map f) => f a -> b -> f b
replace as b = map (const b) as
-- | Given a datatype @F a b@, @bimap f g@ applies the function @f :: a -> c@ to
-- every @a@-element and the function @g :: b -> d@ to every @b@-element. The
-- result is a value with transformed elements: @F c d@.
bimap :: (BiFRep2 Map f) => (a -> c) -> (b -> d) -> f a b -> f c d
bimap f g = selMap (bifrep2 (Map f) (Map g))
-- | Cast a value of one type into a value of another. This is a configurable
-- function that allows you to define your own type-safe conversions for a
-- variety of types.
--
-- @cast@ works with instances of @'Rep' ('Map' i) o@ in which you choose the
-- input type @i@ and the output type @o@ and implement the function of type @i
-- -> o@.
--
-- Here are some examples of instances (and flags you will need or want):
--
-- > {-# LANGUAGE MultiParamTypeClasses #-}
-- > {-# LANGUAGE FlexibleContexts #-}
-- > {-# LANGUAGE FlexibleInstances #-}
-- > {-# OPTIONS_GHC -fno-warn-orphans #-}
--
-- @
-- instance 'Rep' ('Map' 'Int') 'Char' where
-- 'rep' = 'Map' 'chr'
-- @
--
-- @
-- instance 'Rep' ('Map' 'Float') 'Double' where
-- 'rep' = 'Map' 'realToFrac'
-- @
--
-- @
-- instance 'Rep' ('Map' 'Integer') 'Integer' where
-- 'rep' = 'Map' (+42)
-- @
--
-- There are no pre-defined instances, and a call to @cast@ will not compile if
-- no instances for the input and output type pair is found, so you must define
-- instances in order to use @cast@.
cast :: (Rep (Map a) b) => a -> b
cast = selMap rep