{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE StandaloneDeriving #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_GHC -fno-warn-missing-signatures #-} {-# OPTIONS_GHC -fno-warn-deprecations #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-} import Data.Functor import Data.Maybe import Data.Typeable import Test.QuickCheck.All (quickCheckAll) import Test.QuickCheck hiding ((===)) import Test.Feat import Data.List.NonEmpty (NonEmpty) import qualified Data.List.NonEmpty as NEL import Data.Monoid.Action import Data.Semigroup import Data.Tree.DUAL data DUALTreeExpr d u a l = EEmpty | ELeaf u l | ELeafU u | EConcat (NonEmpty (DUALTreeExpr d u a l)) | EAct d (DUALTreeExpr d u a l) | EAnnot a (DUALTreeExpr d u a l) deriving (Show, Typeable) deriveEnumerable ''NonEmpty deriveEnumerable ''DUALTreeExpr buildTree :: (Semigroup u, Semigroup d, Action d u) => DUALTreeExpr d u a l -> DUALTree d u a l buildTree EEmpty = empty buildTree (ELeaf u l) = leaf u l buildTree (ELeafU u) = leafU u buildTree (EConcat ts) = sconcat (NEL.map buildTree ts) buildTree (EAct d t) = applyD d (buildTree t) buildTree (EAnnot a t) = annot a (buildTree t) -- buildTree' :: DUALTreeExpr D U () Bool -> DUALTree D U () Bool -- buildTree' = buildTree instance Num a => Action (Product a) (Sum a) where act (Product p) (Sum s) = Sum (p * s) type U = Sum Int type D = Product Int deriving instance Typeable Sum deriving instance Typeable Product deriveEnumerable ''Sum deriveEnumerable ''Product type T = DUALTree D U Bool Bool instance Arbitrary T where arbitrary = buildTree <$> sized uniform prop_leaf_u :: U -> Bool prop_leaf_u u = getU (leaf u ()) == Just u prop_leafU_u :: U -> Bool prop_leafU_u u = getU (leafU u) == Just u prop_applyUpre :: U -> T -> Bool prop_applyUpre u t = getU (applyUpre u t) == Just (u <> fromMaybe mempty (getU t)) prop_applyUpost :: U -> T -> Bool prop_applyUpost u t = getU (applyUpost u t) == Just (fromMaybe mempty (getU t) <> u) -------------------------------------------------- -- Monoid laws -------------------------------------------------- prop_mempty_idL :: T -> Bool prop_mempty_idL t = mempty <> t == t prop_mempty_idR :: T -> Bool prop_mempty_idR t = t <> mempty == t infix 4 === t1 === t2 = flatten t1 == flatten t2 -- mappend is associative up to flattening. prop_mappend_assoc :: T -> T -> T -> Bool prop_mappend_assoc t1 t2 t3 = (t1 <> t2) <> t3 === t1 <> (t2 <> t3) -------------------------------------------------- -- Action laws -------------------------------------------------- prop_mempty_act :: T -> Bool prop_mempty_act t = applyD mempty t === t prop_mappend_act :: D -> D -> T -> Bool prop_mappend_act d1 d2 t = applyD d1 (applyD d2 t) == applyD (d1 <> d2) t prop_act_mempty :: D -> Bool prop_act_mempty d = applyD d (mempty :: T) == mempty prop_act_mappend :: D -> T -> T -> Bool prop_act_mappend d t1 t2 = applyD d (t1 <> t2) === applyD d t1 <> applyD d t2 return [] main = $quickCheckAll