{- Copyright (C) 2010 Andrejs Sisojevs All rights reserved. For license and copyright information, see the file COPYRIGHT -} -------------------------------------------------------------------------- -------------------------------------------------------------------------- {-# LANGUAGE MultiParamTypeClasses #-} import Data.Cardinality import Data.List import System.IO data MyContainer a = MyContainer { field_1 :: Maybe a , field_2 :: (a, a, a) , field_3 :: a , field_4 :: [a] } deriving (Show) emptiestMyContainer :: MyContainer Int emptiestMyContainer = MyContainer Nothing (1,1,1) 1 [] instance HasCard (MyContainer a) where cardOf mc = sumLCs [ cardOf $ field_1 mc -- 0..1 , cardOf $ field_2 mc -- 3 (uses instance HasCard (a,a,a)) , preciseC 1 , cardOf $ field_4 mc -- 0..Inf ] -- = 4..Inf instance HasCardT MyContainer where cardOfT = cardOf instance HasCardConstr (MyContainer a) where cardinalityConstraintOf mc_a = cardinalityRange (cardOf emptiestMyContainer) infiniteC instance HasCardConstrT MyContainer where cardinalityConstraintOfT = cardinalityConstraintOf instance HasCardUCT (MyContainer a) [a] where uContTrans mc_a = uContTrans (field_1 mc_a) ++ uContTrans (field_2 mc_a) ++ [field_3 mc_a] ++ field_4 mc_a instance HasCardUCT_T MyContainer [] where uContTransT = uContTrans -- We will use this function to instaniate both @HasCardUCT@ and @HasCardUCT_T@. -- They must use different error throwers, that's why had to define transform -- outside of instances - in order to avoid doublecoding the same thing. __uContTrans :: (TransformError_Details -> MyContainer a) -> [a] -> MyContainer a __uContTrans error_fun a_list = result where result = case a_list of (e1 : e2 : e3 : e4 : rest_a_list_1) -> case rest_a_list_1 of (e5 : rest_a_list_2) -> MyContainer { field_1 = Just e1 , field_2 = (e2,e3,e4) , field_3 = e5 , field_4 = rest_a_list_2 } _ -> MyContainer { field_1 = Nothing , field_2 = (e1,e2,e3) , field_3 = e4 , field_4 = rest_a_list_1 } _ -> error_fun "not enough elements in list" instance HasCardUCT [a] (MyContainer a) where uContTrans = __uContTrans (uContError "[a]" "MyContainer a") instance HasCardUCT_T [] MyContainer where uContTransT = __uContTrans (uContErrorT "[]" "MyContainer") main = do let f pr c = pr ++ (concat $ intersperse "\n" $ map show c) let output1 = f "Initial MyContainers:\n" initial_containers let output2 = f "MyContainers trasformed to lists:\n" initial_containers2lists let output3 = f "Initial lists:\n" initial_lists let output4 = f "Lists trasformed to MyContainers:\n" initial_lists2containers putStrLn output1 pressAnyKey putStrLn output2 pressAnyKey putStrLn output3 pressAnyKey putStrLn output4 pressAnyKey where initial_containers :: [MyContainer Int] initial_lists :: [[Int]] initial_containers2lists :: [Maybe [Int]] initial_lists2containers :: [Maybe (MyContainer Int)] --------------------------------- initial_containers = [ MyContainer (Just 1) (2,3,4) 5 [6,7,8,9,10] , MyContainer (Just 1) (2,3,4) 5 [] , MyContainer Nothing (2,3,4) 5 [6,7,8,9,10] , MyContainer Nothing (2,3,4) 5 [] ] initial_lists = [ [] , [1] , [1..3] , [1..4] , [1..10] , [1..5] , [2..10] ] initial_containers2lists = map sContTrans initial_containers initial_lists2containers = map sContTrans initial_lists --------------------------------------------------------------- -- helpers infixr 1 << (<<) :: Monad m => m b -> m a -> m b f << x = x >> f putStrLn_paged :: Int -> String -> IO () putStrLn_paged page_size s = f $ lines s where f lines_list = let (to_print, to_next_itera) = splitAt page_size lines_list in do putStrLn (concat $ intersperse "\n" to_print) case null to_next_itera of True -> return () False -> f to_next_itera << pressAnyKey pressAnyKey = hGetChar stdin << putStrLn "\n-------Press any key to continue...-------"