packages feed

RepLib-0.2.1: examples/Main.hs

-- OPTIONS -fglasgow-exts -fth -fallow-undecidable-instances 
{-# LANGUAGE TemplateHaskell, UndecidableInstances, ScopedTypeVariables, FlexibleInstances, MultiParamTypeClasses  #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Main
-- Copyright   :  (c) The University of Pennsylvania, 2006
-- License     :  BSD
-- 
-- Maintainer  :  sweirich@cis.upenn.edu
-- Stability   :  experimental
-- Portability :  non-portable
--
-- A file demonstrating the use of RepLib
--
-----------------------------------------------------------------------------

module Main where

import Data.RepLib
import Language.Haskell.TH


-- For each datatype that we define, we need to also create its representation. 
-- The template Haskell function derive does this automatically for 
-- each type.

data Tree a = Leaf a | Node (Tree a) (Tree a)
$(derive [''Tree])

data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
$(derive [''Day])

-- Note, for mutually recursive datatypes, use "derive" and give list
-- of type names.

-- Note also that the functions of RepLib can cooperate with the 
-- traditional 'deriving' mechanism
data Company   = C [Dept]                 deriving (Eq, Ord, Show)         
data Dept      = D String Manager [CUnit] deriving (Eq, Ord, Show)         
data Manager   = M Employee               deriving (Eq, Ord, Show)         
data CUnit     = PU Employee | DU Dept    deriving (Eq, Ord, Show)        
data Employee  = E Person Salary          deriving (Eq, Ord, Show)         
data Person    = P String                 deriving (Eq, Ord, Show)         
data Salary    = S Float                  deriving (Eq, Ord, Show)         

$(derive 
    [''Company, 
     ''Dept, 
     ''CUnit, 
     ''Employee, 
 	  ''Manager, 
 	  ''Person, 
 	  ''Salary])


-- 
-- Some sample data for these types
-- 
t1 :: Tree Int 
t1 = Node (Node (Leaf 3) (Leaf 4)) (Node (Leaf 5) (Leaf 6))

t2 :: Tree Int 
t2 = Node (Node (Leaf 0) (Leaf 7)) (Leaf 20)

s1 :: Company
s1 = C [D "Types" (M (E (P "Stephanie") (S 1000.0))) 
            [PU (E (P "Michael") (S 50)), 
             PU (E (P "Samuel") (S 50)),
             PU (E (P "Theodore") (S 50))],
        D "Terms" (M (E (P "Stephanie") (S 200)))
            [DU (D "Shipping" (M (E (P "Alice") (S 3000)))
                [])]]
                 

--
-- Prelude operations.
--
-- Note that we didn't derive Eq, Ord, Bounded or Show for "Day" and "Tree". We can 
-- do that now with operations from RepLib.PreludeLib.

-- for Day
instance Eq Day      where 
  (==) = eqR1 rep1
instance Ord Day     where 
  compare = compareR1 rep1
instance Bounded Day where 
  minBound = minBoundR1 rep1 
  maxBound = maxBoundR1 rep1
instance Show Day    where 
  showsPrec = showsPrecR1 rep1

-- for Tree
instance (Rep a, Eq a) => Eq (Tree a)     where (==) = eqR1 rep1
instance (Rep a, Show a) => Show (Tree a) where showsPrec = showsPrecR1 rep1
instance (Rep a, Ord a) => Ord (Tree a)   where compare = compareR1 rep1

-- Besides the prelude operations, RepLib provides a number of other 
-- type-indexed operations.

--
-- Instances for RepLib.Lib operations
--

-- Generate creates arbitrary elements of a type, up to a certain depth.
instance Generate Day
instance Generate a => Generate (Tree a)
instance Generate Company
instance Generate Dept
instance Generate Manager
instance Generate CUnit
instance Generate Employee
instance Generate Person
instance Generate Salary					  
	 

-- Sum adds together all of the Ints in a datastructure
instance GSum a => GSum (Tree a)
instance GSum Company
instance GSum Dept
instance GSum Manager
instance GSum CUnit
instance GSum Employee
instance GSum Person
instance GSum Salary

-- Shrink creates smaller versions of a data structure.
instance Shrink a => Shrink (Tree a)

-- 
-- SYB Style operations
-- 
-- RepLib also supports many of the combinators from the SYB library. For example, 
-- we can include the following code from the "Paradise" benchmark that gives everyone 
-- in the company a raise.

-- Increase salary by percentage
increase :: Float -> Company -> Company
increase k = everywhere (mkT (incS k))

-- "interesting" code for increase
incS :: Float -> Salary -> Salary
incS k (S s) = S (s * (1+k))


--
-- Generalized folds
--
-- finally, we define generalized versions of fold left and 
-- fold right for the Tree type constructor.
instance Fold Tree where
  foldRight op = rreduceR1 (rTree1 (RreduceD { rreduceD = op })
                                   (RreduceD { rreduceD = foldRight op}))
  foldLeft  op = lreduceR1 (rTree1 (LreduceD { lreduceD = op })
                                   (LreduceD { lreduceD = foldLeft op }))

main = do print (minBound :: Day)
          print (maxBound :: Day)
          print t1
          print s1
          print (Monday < Tuesday)
          print (t1 < t2)
--          
          print (generate 7 :: [Day])
          print (generate 3 :: [Tree Int])
          print (generate 7 :: [Company])
--
          print (subtrees t1)
          print (gsum t1)
          print (gsum t2)
--
          print (increase 0.1 s1)
          print (s1 < (increase 0.2 s1))
-- 
          print (gproduct t1)
          print (count t1)