-----------------------------------------------------------------------------
-- |
-- Module      :  ForSyDe.Shallow.AbsentExt
-- Copyright   :  (c) SAM Group, KTH/ICT/ECS 2007-2008
-- License     :  BSD-style (see the file LICENSE)
-- 
-- Maintainer  :  forsyde-dev@ict.kth.se
-- Stability   :  experimental
-- Portability :  portable
--
-- The 'AbstExt' is used to extend existing data types with the value
--  \'absent\', which models the absence of a value.
-- 
-----------------------------------------------------------------------------
module ForSyDe.Shallow.AbsentExt( 
		  AbstExt (Abst, Prst), fromAbstExt, abstExt, psi, 
	          isAbsent, isPresent, abstExtFunc)
	        where




-- |The data type 'AbstExt' has two constructors. The constructor 'Abst' is used to model the absence of a value, while the constructor 'Prst' is used to model present values.
data AbstExt a		       =  Abst   
			       |  Prst a deriving (Eq)



-- |The function 'fromAbstExt' converts a value from a extended value.
fromAbstExt	       :: a -> AbstExt a -> a
-- |The functions 'isPresent' checks for the presence of a value.
isPresent	       :: AbstExt a -> Bool
-- |The functions 'isAbsent' checks for the absence of a value.
isAbsent	       :: AbstExt a -> Bool
-- |The function 'abstExtFunc' extends a function in order to process absent extended values. If the input is (\"bottom\"), the output will also be  (\"bottom\").
abstExtFunc	       :: (a -> b) -> AbstExt a -> AbstExt b
-- | The function 'psi' is identical to 'abstExtFunc' and should be used in future.
psi :: (a -> b) -> AbstExt a -> AbstExt b
-- | The function 'abstExt' converts a usual value to a present value. 
abstExt :: a -> AbstExt a






-- Implementation of Library Functions

-- | The data type 'AbstExt' is defined as an instance of 'Show' and 'Read'. \'_\' represents the value 'Abst' while a present value is represented with its value, e.g.  'Prst' 1 is represented as \'1\'.
instance Show a => Show (AbstExt a) where
	 showsPrec _ x	       = showsAbstExt x

showsAbstExt :: Show a => AbstExt a -> [Char] -> [Char]
showsAbstExt Abst	       = (++) "_"       
showsAbstExt (Prst x)	       = (++) (show x)

instance Read a => Read (AbstExt a) where
 	 readsPrec _ x	       =  readsAbstExt x 

readsAbstExt		       :: (Read a) => ReadS (AbstExt a)
readsAbstExt s		       =     [(Abst, r1)    | ("_", r1) <- lex s]
                                  ++ [(Prst x, r2)  | (x, r2) <- reads s]

abstExt v		       =  Prst v

fromAbstExt x Abst	       =  x   
fromAbstExt _ (Prst y)	       =  y   

isPresent Abst		       =  False
isPresent (Prst _)	       =  True

isAbsent		       =  not . isPresent

abstExtFunc f		       = f' 
  where f' Abst		       = Abst
	f' (Prst x)	       = Prst (f x)


psi			       = abstExtFunc