kure-2.0.0: Language/KURE/Injection.hs
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
-- |
-- Module: Language.KURE.Injection
-- Copyright: (c) 2012 The University of Kansas
-- License: BSD3
--
-- Maintainer: Neil Sculthorpe <neil@ittc.ku.edu>
-- Stability: beta
-- Portability: ghc
--
-- This module provides a type class for injective functions (and their retractions),
-- and some useful interactions with 'Translate'.
--
-- A particularly useful instance of 'Injection' is from @a@ to 'Generic' @a@,
-- and that case is the primary purpose of most of these combinators.
module Language.KURE.Injection
( -- * Injection Class
Injection(..)
-- * Monad Injections
, injectM
, retractM
-- * Translate Injections
, injectT
, retractT
, extractT
, promoteT
, extractR
, promoteR
-- * Lens Injections
, injectL
, retractL
) where
import Control.Monad
import Control.Arrow
import Language.KURE.Translate
-------------------------------------------------------------------------------
-- | A class of injective functions from @a@ to @b@, and their retractions.
-- The following law is expected to hold:
--
-- > retract (inject a) == Just a
class Injection a b where
inject :: a -> b
retract :: b -> Maybe a
-- | There is an identity injection for all types.
instance Injection a a where
inject = id
retract = Just
instance Injection a (Maybe a) where
inject = Just
retract = id
-------------------------------------------------------------------------------
-- | Injects a value and lifts it into a 'Monad'.
injectM :: (Monad m, Injection a a') => a -> m a'
injectM = return . inject
-- | Retracts a value and lifts it into a 'MonadPlus', producing 'mzero' if the retraction fails.
retractM :: (MonadPlus m, Injection a a') => a' -> m a
retractM = maybe mzero return . retract
-------------------------------------------------------------------------------
-- | Lifted 'inject'.
injectT :: (Monad m, Injection a a') => Translate c m a a'
injectT = arr inject
-- | Lifted 'retract', the 'Translate' fails if the retraction fails.
retractT :: (MonadPlus m, Injection a a') => Translate c m a' a
retractT = contextfreeT retractM
-- | Convert a 'Translate' over an injected value into a 'Translate' over a non-injected value.
extractT :: (Monad m, Injection a a') => Translate c m a' b -> Translate c m a b
extractT t = injectT >>> t
-- | Promote a 'Translate' over a value into a 'Translate' over an injection of that value,
-- (failing if that injected value cannot be retracted).
promoteT :: (MonadPlus m, Injection a a') => Translate c m a b -> Translate c m a' b
promoteT t = retractT >>> t
-- | Convert a 'Rewrite' over an injected value into a 'Rewrite' over a retraction of that value,
-- (failing if that injected value cannot be retracted).
extractR :: (MonadPlus m, Injection a a') => Rewrite c m a' -> Rewrite c m a
extractR r = injectT >>> r >>> retractT
-- | Promote a 'Rewrite' into over a value into a 'Rewrite' over an injection of that value,
-- (failing if that injected value cannot be retracted).
promoteR :: (MonadPlus m, Injection a a') => Rewrite c m a -> Rewrite c m a'
promoteR r = retractT >>> r >>> injectT
-------------------------------------------------------------------------------
-- | A 'Lens' to the injection of a value.
injectL :: (MonadPlus m, Injection a a') => Lens c m a a'
injectL = lens $ \ c a -> return ((c, inject a), retractM)
-- | A 'Lens' to the retraction of a value.
retractL :: (MonadPlus m, Injection a a') => Lens c m a' a
retractL = lens $ \ c -> retractM >=> (\ a -> return ((c,a), injectM))
-------------------------------------------------------------------------------