import qualified Data.Map as Map
data Color = Red | Yellow | Green | Blue | White | Black deriving (Show)
data Property = ColorProp Color | SizeProp Integer deriving (Show)
type Properties = Map.Map String Property
class HasProp o where
getProps :: o -> Properties
setProps :: o -> Properties -> o
getProp :: (Monad m) => String -> o -> m Property
getProp name obj = Map.lookup name (getProps obj)
getPropWithDefault :: String -> Property -> o -> Property
getPropWithDefault name def obj = Map.findWithDefault def name (getProps obj)
setProp :: String -> o -> Property -> o
setProp name obj prop = setProps obj (Map.insert name prop (getProps obj))
class HasProp o => Colored o where
color :: o -> Color
color obj = col where ColorProp col = getPropWithDefault "color" (ColorProp Black) obj
setColor :: o -> Color -> o
setColor obj col = setProp "color" obj (ColorProp col)
class HasProp o => Sized o where
size :: o -> Integer
size obj = s where SizeProp s = getPropWithDefault "size" (SizeProp 10) obj
setSize :: o -> Integer -> o
setSize obj s = setProp "size" obj (SizeProp s)
data Cube = Cube { cube_props :: Properties } deriving (Show)
data Car = Car { car_props :: Properties } deriving (Show)
default_cube = Cube { cube_props = Map.empty }
default_car = Car { car_props = Map.empty }
instance HasProp Cube
where
getProps = cube_props
setProps obj props = obj { cube_props = props }
instance HasProp Car
where
getProps = car_props
setProps obj props = obj { car_props = props }
instance Colored Cube
instance Colored Car
instance Sized Car
main = putStrLn (show (color (default_car `setColor` Red)))
import qualified Data.Map as Map
data Color = Red | Yellow | Green | Blue | White | Black deriving (Show)
data Property = ColorProp | SizeProp deriving (Eq, Ord, Show)
data PropertyValue = ColorValue Color | SizeValue Integer deriving (Show)
type Properties = Map.Map Property PropertyValue
class HasProp o where
getProps :: o -> Properties
setProps :: o -> Properties -> o
getProp :: (Monad m) => Property -> o -> m PropertyValue
getProp prop obj = Map.lookup prop (getProps obj)
getPropWithDefault :: Property -> PropertyValue -> o -> PropertyValue
getPropWithDefault prop def obj = Map.findWithDefault def prop (getProps obj)
setProp :: Property -> o -> PropertyValue -> o
setProp prop obj value = setProps obj (Map.insert prop value (getProps obj))
class HasProp o => Colored o where
color :: o -> Color
color obj = col where ColorValue col = getPropWithDefault ColorProp (ColorValue Black) obj
setColor :: o -> Color -> o
setColor obj col = setProp ColorProp obj (ColorValue col)
class HasProp o => Sized o where
size :: o -> Integer
size obj = s where SizeValue s = getPropWithDefault SizeProp (SizeValue 10) obj
setSize :: o -> Integer -> o
setSize obj s = setProp SizeProp obj (SizeValue s)
data Cube = Cube { cube_props :: Properties } deriving (Show)
data Car = Car { car_props :: Properties } deriving (Show)
default_cube = Cube { cube_props = Map.empty }
default_car = Car { car_props = Map.empty }
instance HasProp Cube
where
getProps = cube_props
setProps obj props = obj { cube_props = props }
instance HasProp Car
where
getProps = car_props
setProps obj props = obj { car_props = props }
instance Colored Cube
instance Colored Car
instance Sized Car
main = putStrLn (show (color (default_car `setColor` Red)))
module Records where
import Data.Generics.Basics
import Data.Generics.Aliases
import Data.Generics.Schemes
import Control.Monad
import Data.Maybe
greplace :: forall a b. (Data a, Typeable b) => a -> b -> Maybe a
greplace x y = once (return Nothing `extM` (const (return y))) x
once:: MonadPlus m => GenericM m -> GenericM m
once f x = f x `mplus` gmapMo (once f) x
data Color = Red | Yellow | Green | Blue | White | Black deriving (Show, Data, Typeable)
data Size = Size Int deriving (Show, Data, Typeable)
data Car = Car Color Size deriving (Data, Typeable, Show)
data Cube = Cube Color deriving (Data, Typeable, Show)
class Data a => HasColor a where
getColor :: a -> Color
getColor = fromJust . gfindtype
setColor :: a -> Color -> a
setColor = (fromJust .) . greplace
class Data a => HasSize a where
getSize :: a -> Size
getSize = fromJust . gfindtype
setSize :: a -> Size -> a
setSize = (fromJust .) . greplace
instance HasColor Car
instance HasColor Cube
instance HasSize Car
data Size = Size Int deriving (Show, Data, Typeable)
unSize Size a = a
class Data a => HasSize a where
getSize :: a -> Int
getSize = unSize . fromJust . gfindtype
setSize :: a -> Int -> a
setSize = (fromJust .) . (. Size) . greplace