{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} #if __GLASGOW_HASKELL__ >= 705 {-# LANGUAGE DataKinds #-} {-# LANGUAGE PolyKinds #-} #endif {-# OPTIONS_GHC -fno-warn-orphans #-} module ExampleSpec (main, spec) where import Generics.Deriving import Generics.Deriving.TH import GHC.Exts (Addr#, Char#, Double#, Float#, Int#, Word#) import Prelude hiding (Either(..)) import Test.Hspec (Spec, describe, hspec, it, parallel, shouldBe) import qualified Text.Read.Lex (Lexeme) main :: IO () main = hspec spec spec :: Spec spec = parallel $ do describe "[] and Maybe tests" $ do it "gshow hList" $ gshow hList `shouldBe` "[1,2,3,4,5,6,7,8,9,10]" it "gshow (children maybe2)" $ gshow (children maybe2) `shouldBe` "[]" it "gshow (transform (const \"abc\") [])" $ gshow (transform (const "abc") []) `shouldBe` "\"abc\"" it "gshow (transform double hList)" $ gshow (transform double hList) `shouldBe` "[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10]" it "gshow (geq hList hList)" $ gshow (geq hList hList) `shouldBe` "True" it "gshow (geq maybe1 maybe2)" $ gshow (geq maybe1 maybe2) `shouldBe` "False" it "gshow (take 5 genum)" $ gshow (take 5 (genum :: [Maybe Int])) `shouldBe` "[Nothing,Just 0,Just -1,Just 1,Just -2]" it "gshow (take 15 genum)" $ gshow (take 15 (genum :: [[Int]])) `shouldBe` "[[],[0],[0,0],[-1],[0,0,0],[-1,0],[1],[0,-1],[-1,0,0],[1,0],[-2],[0,0,0,0],[-1,-1],[1,0,0],[-2,0]]" it "gshow (range ([0], [1]))" $ gshow (range ([0], [1::Int])) `shouldBe` "[[0],[0,0],[-1],[0,0,0],[-1,0]]" it "gshow (inRange ([0], [3,5]) hList)" $ gshow (inRange ([0], [3,5::Int]) hList) `shouldBe` "False" describe "Tests for Tree" $ do it "gshow tree" $ gshow tree `shouldBe` "Branch 2 Empty (Branch 1 Empty Empty)" it "gshow (children tree)" $ gshow (children tree) `shouldBe` "[Empty,Branch 1 Empty Empty]" it "gshow (descend (descend (\\_ -> Branch 0 Empty Empty)) tree)" $ gshow (descend (descend (\_ -> Branch 0 Empty Empty)) tree) `shouldBe` "Branch 2 Empty (Branch 1 (Branch 0 Empty Empty) (Branch 0 Empty Empty))" it "gshow (context tree [Branch 1 Empty Empty,Empty])" $ gshow (context tree [Branch 1 Empty Empty,Empty]) `shouldBe` "Branch 2 (Branch 1 Empty Empty) Empty" it "gshow (transform upgradeTree tree)" $ gshow (transform upgradeTree tree) `shouldBe` "Branch 3 (Branch 0 Empty Empty) (Branch 2 (Branch 0 Empty Empty) (Branch 0 Empty Empty))" it "gshow (take 10 genum)" $ do gshow (take 10 (genum :: [Tree])) `shouldBe` "[Empty,Branch 0 Empty Empty,Branch 0 Empty (Branch 0 Empty Empty),Branch -1 Empty Empty,Branch 0 (Branch 0 Empty Empty) Empty,Branch -1 Empty (Branch 0 Empty Empty),Branch 1 Empty Empty,Branch 0 Empty (Branch 0 Empty (Branch 0 Empty Empty)),Branch -1 (Branch 0 Empty Empty) Empty,Branch 1 Empty (Branch 0 Empty Empty)]" describe "Tests for List" $ do it "gshow (gmap fromEnum list)" $ gshow (gmap fromEnum list) `shouldBe` "Cons 112 (Cons 113 Nil)" it "gshow (gmap gshow listlist)" $ gshow (gmap gshow listlist) `shouldBe` "Cons \"Cons 'p' (Cons 'q' Nil)\" (Cons \"Nil\" Nil)" it "gshow list" $ gshow list `shouldBe` "Cons 'p' (Cons 'q' Nil)" it "gshow listlist" $ gshow listlist `shouldBe` "Cons (Cons 'p' (Cons 'q' Nil)) (Cons Nil Nil)" it "gshow (children list)" $ gshow (children list) `shouldBe` "[Cons 'q' Nil]" it "gshow (children listlist)" $ gshow (children listlist) `shouldBe` "[Cons Nil Nil]" describe "Tests for Rose" $ do it "gshow rose1" $ gshow rose1 `shouldBe` "Rose [1,2] [Rose [3,4] [],Rose [5] []]" it "gshow (gmap gshow rose1)" $ gshow (gmap gshow rose1) `shouldBe` "Rose [\"1\",\"2\"] [Rose [\"3\",\"4\"] [],Rose [\"5\"] []]" describe "Tests for GRose" $ do it "gshow grose1" $ gshow grose1 `shouldBe` "GRose [1,2] [GRose [3] [],GRose [] []]" it "gshow (gmap gshow grose1)" $ gshow (gmap gshow grose1) `shouldBe` "GRose [\"1\",\"2\"] [GRose [\"3\"] [],GRose [] []]" describe "Tests for Either" $ do it "gshow either1" $ gshow either1 `shouldBe` "Left Right 'p'" it "gshow (gmap gshow either1)" $ gshow (gmap gshow either1) `shouldBe` "Left Right \"'p'\"" describe "Tests for Nested" $ do it "gshow nested" $ gshow nested `shouldBe` "Nested {value = 1, rec = Nested {value = [2], rec = Nested {value = [[3],[4,5],[]], rec = Leaf}}}" it "gshow (gmap gshow nested)" $ gshow (gmap gshow nested) `shouldBe` "Nested {value = \"1\", rec = Nested {value = [\"2\"], rec = Nested {value = [[\"3\"],[\"4\",\"5\"],[]], rec = Leaf}}}" describe "Tests for Bush" $ do it "gshow bush1" $ gshow bush1 `shouldBe` "BushCons 0 (BushCons (BushCons 1 BushNil) BushNil)" it "gshow (gmap gshow bush1)" $ gshow (gmap gshow bush1) `shouldBe` "BushCons \"0\" (BushCons (BushCons \"1\" BushNil) BushNil)" ------------------------------------------------------------------------------- -- Example: Haskell's lists and Maybe ------------------------------------------------------------------------------- hList:: [Int] hList = [1..10] maybe1, maybe2 :: Maybe (Maybe Char) maybe1 = Nothing maybe2 = Just (Just 'p') double :: [Int] -> [Int] double [] = [] double (x:xs) = x:x:xs ------------------------------------------------------------------------------- -- Example: trees of integers (kind *) ------------------------------------------------------------------------------- data Tree = Empty | Branch Int Tree Tree instance GShow Tree where gshowsPrec = gshowsPrecdefault instance Uniplate Tree where children = childrendefault context = contextdefault descend = descenddefault descendM = descendMdefault transform = transformdefault transformM = transformMdefault instance GEnum Tree where genum = genumDefault upgradeTree :: Tree -> Tree upgradeTree Empty = Branch 0 Empty Empty upgradeTree (Branch n l r) = Branch (succ n) l r tree :: Tree tree = Branch 2 Empty (Branch 1 Empty Empty) ------------------------------------------------------------------------------- -- Example: lists (kind * -> *) ------------------------------------------------------------------------------- data List a = Nil | Cons a (List a) instance GFunctor List where gmap = gmapdefault instance (GShow a) => GShow (List a) where gshowsPrec = gshowsPrecdefault instance (Uniplate a) => Uniplate (List a) where children = childrendefault context = contextdefault descend = descenddefault descendM = descendMdefault transform = transformdefault transformM = transformMdefault list :: List Char list = Cons 'p' (Cons 'q' Nil) listlist :: List (List Char) listlist = Cons list (Cons Nil Nil) -- ["pq",""] ------------------------------------------------------------------------------- -- Example: Type composition ------------------------------------------------------------------------------- data Rose a = Rose [a] [Rose a] instance (GShow a) => GShow (Rose a) where gshowsPrec = gshowsPrecdefault instance GFunctor Rose where gmap = gmapdefault -- Example usage rose1 :: Rose Int rose1 = Rose [1,2] [Rose [3,4] [], Rose [5] []] ------------------------------------------------------------------------------- -- Example: Higher-order kinded datatype, type composition ------------------------------------------------------------------------------- data GRose f a = GRose (f a) (f (GRose f a)) deriving instance Functor f => Functor (GRose f) instance (GShow (f a), GShow (f (GRose f a))) => GShow (GRose f a) where gshowsPrec = gshowsPrecdefault instance (Functor f, GFunctor f) => GFunctor (GRose f) where gmap = gmapdefault grose1 :: GRose [] Int grose1 = GRose [1,2] [GRose [3] [], GRose [] []] ------------------------------------------------------------------------------- -- Example: Two parameters, nested on other parameter ------------------------------------------------------------------------------- data Either a b = Left (Either [a] b) | Right b instance (GShow a, GShow b) => GShow (Either a b) where gshowsPrec = gshowsPrecdefault instance GFunctor (Either a) where gmap = gmapdefault either1 :: Either Int Char either1 = Left either2 either2 :: Either [Int] Char either2 = Right 'p' ------------------------------------------------------------------------------- -- Example: Nested datatype, record selectors ------------------------------------------------------------------------------- data Nested a = Leaf | Nested { value :: a, rec :: Nested [a] } deriving Functor instance (GShow a) => GShow (Nested a) where gshowsPrec = gshowsPrecdefault instance GFunctor Nested where gmap = gmapdefault nested :: Nested Int nested = Nested { value = 1, rec = Nested [2] (Nested [[3],[4,5],[]] Leaf) } ------------------------------------------------------------------------------- -- Example: Nested datatype Bush (minimal) ------------------------------------------------------------------------------- data Bush a = BushNil | BushCons a (Bush (Bush a)) deriving Functor instance GFunctor Bush where gmap = gmapdefault instance (GShow a) => GShow (Bush a) where gshowsPrec = gshowsPrecdefault bush1 :: Bush Int bush1 = BushCons 0 (BushCons (BushCons 1 BushNil) BushNil) ------------------------------------------------------------------------------- -- Example: Double type composition (minimal) ------------------------------------------------------------------------------- data Weird a = Weird [[[a]]] deriving Show instance GFunctor Weird where gmap = gmapdefault -------------------------------------------------------------------------------- -- Temporary tests for TH generation -------------------------------------------------------------------------------- data Empty a data (:/:) f a = MyType1Nil | MyType1Cons { _myType1Rec :: (f :/: a), _myType2Rec :: MyType2 } | MyType1Cons2 (f :/: a) Int a (f a) | (f :/: a) :/: MyType2 data MyType2 = MyType2 Float ([] :/: Int) data PlainHash a = Hash a Addr# Char# Double# Float# Int# Word# -- Test to see if generated names are unique data Lexeme = Lexeme #if MIN_VERSION_template_haskell(2,7,0) data family MyType3 # if __GLASGOW_HASKELL__ >= 705 (a :: v) (b :: w) (c :: x) (d :: y) (e :: z) # else (a :: *) (b :: *) (c :: * -> *) (d :: *) (e :: *) # endif newtype instance MyType3 (f p) (f p) f p q = MyType3Newtype q data instance MyType3 Bool () f p q = MyType3True | MyType3False data instance MyType3 Int () f p q = MyType3Hash q Addr# Char# Double# Float# Int# Word# #endif ------------------------------------------------------------------------------- -- Template Haskell bits ------------------------------------------------------------------------------- $(deriveAll0 ''Tree) $(deriveAll0And1 ''List) $(deriveAll0And1 ''Rose) $(deriveMeta ''GRose) $(deriveRepresentable0 ''GRose) $(deriveRep1 ''GRose) instance Functor f => Generic1 (GRose f) where type Rep1 (GRose f) = $(makeRep1 ''GRose) f from1 = $(makeFrom1 ''GRose) to1 = $(makeTo1 ''GRose) $(deriveAll0And1 ''Either) $(deriveAll0And1 ''Nested) $(deriveAll0And1 ''Bush) $(deriveAll0And1 ''Weird) $(deriveAll0And1 ''Empty) $(deriveAll0And1 ''(:/:)) $(deriveAll0 ''MyType2) $(deriveAll0And1 ''PlainHash) $(deriveAll0 ''ExampleSpec.Lexeme) $(deriveAll0 ''Text.Read.Lex.Lexeme) #if MIN_VERSION_template_haskell(2,7,0) # if __GLASGOW_HASKELL__ < 705 -- We can't use deriveAll0And1 on GHC 7.4 due to an old bug :( $(deriveMeta 'MyType3Newtype) $(deriveRep0 'MyType3Newtype) $(deriveRep1 'MyType3Newtype) instance Generic (MyType3 (f p) (f p) f p q) where type Rep (MyType3 (f p) (f p) f p q) = $(makeRep0 'MyType3Newtype) f p q from = $(makeFrom0 'MyType3Newtype) to = $(makeTo0 'MyType3Newtype) instance Generic1 (MyType3 (f p) (f p) f p) where type Rep1 (MyType3 (f p) (f p) f p) = $(makeRep1 'MyType3Newtype) f p from1 = $(makeFrom1 'MyType3Newtype) to1 = $(makeTo1 'MyType3Newtype) # else $(deriveAll0And1 'MyType3Newtype) # endif $(deriveAll0And1 'MyType3False) $(deriveAll0And1 'MyType3Hash) #endif