{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE StandaloneDeriving #-}
module Main where
import Generics.MultiRec hiding (show)
import Generics.MultiRec.TH
import Test.QuickCheck
import Test.QuickCheck.Random
import Control.Monad
import Generics.MultiRec.Transformations.Main
import Generics.MultiRec.Transformations.MemoTable
import Criterion.Main
data Tree = Leaf Int | Branch1 Tree Tree | Branch2 Tree Tree | Test [(Tree,Int)]
deriving (Show, Ord, Eq)
data TreeAST :: * -> * where
Tree :: TreeAST Tree
type instance Ixs TreeAST = '[ Tree ]
data Leaf
data Branch1
data Branch2
data Test
instance Constructor Leaf where
conName _ = "Leaf"
instance Constructor Branch1 where
conName _ = "Branch1"
instance Constructor Branch2 where
conName _ = "Branch2"
instance Constructor Test where
conName _ = "Test"
type instance PF TreeAST = (C Leaf (K Int) :+: C Branch1 (I Tree :*: I Tree) :+: C Branch2 (I Tree :*: I Tree) :+: (C Test ([] :.: (I Tree :*: K Int)))) :>: Tree
instance El TreeAST Tree where
proof = Tree
instance Fam TreeAST where
from Tree (Leaf f0)
= Tag (L (C (K f0)))
from Tree (Branch1 f0 f1)
= Tag (R (L (C ((:*:) ((I . I0) f0) ((I . I0) f1)))))
from Tree (Branch2 f0 f1)
= Tag (R (R (L (C ((:*:) ((I . I0) f0) ((I . I0) f1))))))
from Tree (Test f0)
= Tag (R (R (R (C (D [(I . I0) i :*: K t | (i,t) <- f0])))))
to Tree (Tag (L (C f0)))
= Leaf (unK f0)
to Tree (Tag (R (L (C ((:*:) f0 f1)))))
= Branch1 ((unI0 . unI) f0) ((unI0 . unI) f1)
to Tree (Tag (R (R (L (C ((:*:) f0 f1))))))
= Branch2 ((unI0 . unI) f0) ((unI0 . unI) f1)
to Tree (Tag (R (R (R (C (D f0))))))
= Test [((unI0 . unI) t, i) | t :*: K i <- f0]
-- $(deriveAll ''TreeAST)
-- Straight from the QC manual
instance Arbitrary Tree where
shrink (Leaf v) = map Leaf (shrink v)
shrink (Branch1 l r) = [l,r]
shrink (Branch2 l r) = [l,r]
shrink (Test lst) = concatMap (map fst) (shrink lst)
arbitrary = sized tree'
where tree' 0 = liftM Leaf arbitrary
tree' n | n>0 =
oneof [liftM Leaf arbitrary,
liftM2 Branch1 subtree subtree,
liftM2 Branch2 subtree subtree,
liftM Test genLst]
where subtree = tree' (n `div` 2)
genLst = do m <- choose (1,n)
replicateM m (resize (n `div` m) arbitrary)
-- Our diff property
diffCorrect :: Tree -> Tree -> Bool
diffCorrect a b = apply Tree a (diff Tree a b) == Just b
main :: IO ()
main = do
putStrLn "Generating testcases"
cases <- replicateM 40 (liftM2 (,) (generate arbitrary) (generate arbitrary))
putStrLn "Checking correctness"
forM_ cases $ \(a,b) -> do
when (not $ diffCorrect a b) $ putStrLn "Failed diffCorrect"
putStrLn "Benchmarking"
defaultMain [
bench "MultiRec" $ nf (map (uncurry diffCorrect)) cases
]