{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies, FlexibleContexts, UndecidableInstances, OverlappingInstances, IncoherentInstances #-} class SubtypeOf a b | a -> b where upcast :: a -> b downcastSafe :: b -> Maybe a downcast :: b -> a downcast b = case downcastSafe b of Nothing -> error $ "can not downcast the value" Just a -> a class (Ord a) => Rangable t a | t -> a where lowLim :: t -> a highLim :: t -> a class Packable t a | t -> a where pack :: a -> t unpack :: t -> a class MultipleTo t a | t -> a where multiple :: t -> a instance (Num a, Ord a, Rangable range a, Packable range a) => SubtypeOf range a where upcast = unpack downcastSafe b | b >= (lowLim $ pb) && b <= (highLim $ pb) = Just $ pb | otherwise = Nothing where pb = pack b instance (Integral a, Packable range a, MultipleTo range a) => SubtypeOf range a where upcast = unpack downcastSafe b | b `mod` (multiple pb) == 0 = Just pb | otherwise = Nothing where pb = pack b newtype Range1 a = Range1 {unRange1 :: a} deriving Show instance (Num a, Ord a) => Rangable (Range1 a) a where lowLim _ = 0 highLim _ = 10 instance (Num a, Ord a) => Packable (Range1 a) a where pack = Range1 unpack = unRange1 newtype Range2 a = Range2 {unRange2 :: a} deriving Show instance (Num a, Ord a) => Rangable (Range2 a) a where lowLim _ = -10 highLim _ = 200 instance (Num a, Ord a) => Packable (Range2 a) a where pack = Range2 unpack = unRange2