leancheck-1.0.4: test/derive.hs
-- Copyright (c) 2015-2025 Rudy Matela.
-- Distributed under the 3-Clause BSD licence (see the file LICENSE).
{-# LANGUAGE TemplateHaskell, CPP #-}
import Test
-- import Test.LeanCheck -- already exported by Test
import Test.LeanCheck.Derive
import Test.LeanCheck.Utils
import Data.List (sort, isPrefixOf)
-- replication of Haskell's built-in data types
-- in the order of the Haskell98 standard
-- https://www.haskell.org/onlinereport/basic.html
-- with Peanos as a numeric type.
data Peano = Zero | Succ Peano deriving (Eq, Ord, Show)
data Choice = Yes | No deriving (Eq, Ord, Show)
data Lst a = a :- Lst a | Nil deriving (Eq, Ord, Show)
data Duo a b = a :+ b deriving (Eq, Ord, Show)
data Unit = Unit deriving (Eq, Ord, Show)
data Perhaps a = Naught | Precisely a deriving (Eq, Ord, Show)
data Alternatively a b = Sinister a | Dexter b deriving (Eq, Ord, Show)
data Relation = Smaller | Same | Bigger deriving (Eq, Ord, Show)
data Trio a b c = Trio a b c deriving (Eq, Ord, Show)
infixr 5 :-
deriveListable ''Peano
deriveListable ''Choice
deriveListable ''Lst
deriveListable ''Duo
deriveListable ''Unit
deriveListable ''Perhaps
deriveListable ''Alternatively
deriveListable ''Relation
deriveListable ''Trio
-- tree types
data Tree a = Node (Tree a) a (Tree a) | Null deriving (Eq, Ord, Show)
data Bush a = Bush a :-: Bush a | Leaf a deriving (Eq, Ord, Show)
deriveListable ''Tree
deriveListable ''Bush
-- mutually recursive types
data Mutual = Munil | Mutual CoMutual deriving (Eq, Ord, Show)
data CoMutual = CoMunil | CoMutual Mutual deriving (Eq, Ord, Show)
deriveListableCascading ''Mutual
-- newtypes, type synonyms, inner/outer
newtype Novel a = Novel a deriving (Eq, Ord, Show)
data Inner = I deriving (Eq, Ord, Show)
data Outer = O Inner deriving (Eq, Ord, Show)
type Nouter = Novel Outer
deriveListableCascading ''Nouter
-- Complex nested datatype cascade
data Nested = Nested N0 (N1 Int) (N2 Int Int)
newtype N0 = R0 Int
newtype N1 a = R1 a
data N2 a b = R2 a b
deriveListableCascading ''Nested
-- Complex recursive nested datatype cascade
data RN = RN RN0 (RN1 Int) (RN2 Int RN)
data RN0 = Nest0 Int | Recurse0 RN
data RN1 a = Nest1 a | Recurse1 RN
data RN2 a b = Nest2 a b | Recurse2 RN
deriveListableCascading ''RN
-- Those should have no effect (instance already exists):
{- uncommenting those should generate warnings
deriveListable ''Bool
deriveListable ''Maybe
deriveListable ''Either
-}
-- Those should not generate warnings
deriveListableIfNeeded ''Bool
deriveListableIfNeeded ''Maybe
deriveListableIfNeeded ''Either
main :: IO ()
main = mainTest tests 200
tests :: Int -> [Bool]
tests n =
[ True
, [ Zero
, Succ Zero
, Succ (Succ Zero)
, Succ (Succ (Succ Zero))
] `isPrefixOf` list
, [Yes, No] == list
, [ Nil
, Unit :- Nil
, Unit :- Unit :- Nil
, Unit :- Unit :- Unit :- Nil
] `isPrefixOf` list
, [ Nil
, Zero :- Nil
, Zero :- (Zero :- Nil)
, Succ Zero :- Nil
, Zero :- (Zero :- (Zero :- Nil))
, Zero :- (Succ Zero :- Nil)
] `isPrefixOf` list
, list == [Yes :+ Yes, Yes :+ No, No :+ Yes, No :+ No]
, [ Zero :+ Zero
, Zero :+ Succ Zero
, Succ Zero :+ Zero
, Zero :+ Succ (Succ Zero)
, Succ Zero :+ Succ Zero
] `isPrefixOf` list
, list == [Unit]
, list == [Naught, Precisely Unit]
, list == [Naught, Precisely Yes, Precisely No]
, list == [Sinister Yes, Sinister No, Dexter Yes, Dexter No]
, [ Sinister Zero
, Dexter Zero
, Sinister (Succ Zero)
, Dexter (Succ Zero)
, Sinister (Succ (Succ Zero))
, Dexter (Succ (Succ Zero))
] `isPrefixOf` list
, list == [Smaller, Same, Bigger]
, list == [Trio Unit Unit Unit]
, [ Null
, Node Null False Null
, Node Null True Null
, Node Null False (Node Null False Null)
, Node Null False (Node Null True Null)
, Node Null True (Node Null False Null)
] `isPrefixOf` list
, [ Leaf False
, Leaf True
, Leaf False :-: Leaf False
, Leaf False :-: Leaf True
, Leaf True :-: Leaf False
, Leaf True :-: Leaf True
] `isPrefixOf` list
, [ Munil
, Mutual CoMunil
, Mutual (CoMutual Munil)
, Mutual (CoMutual (Mutual CoMunil))
, Mutual (CoMutual (Mutual (CoMutual Munil)))
, Mutual (CoMutual (Mutual (CoMutual (Mutual CoMunil))))
] `isPrefixOf` list
, list == [I]
, list == [O I]
, list == [Novel (O I) :: Nouter]
, map (\Unit -> ()) list =| n |= list
, map (\(Novel x) -> x) list == (list :: [()])
, map (\(Novel x) -> x) list == (list :: [Bool])
, map (\(Novel x) -> x) list =| n |= (list :: [Int])
, map (\(x :+ y) -> (x,y)) list == (list :: [((),())])
, map (\(x :+ y) -> (x,y)) list == (list :: [(Bool,Bool)])
, map (\(x :+ y) -> (x,y)) list =| n |= (list :: [(Int,Int)])
, map (\(Trio x y z) -> (x,y,z)) list == (list :: [((),(),())])
, map (\(Trio x y z) -> (x,y,z)) list == (list :: [(Bool,Bool,Bool)])
, map (\(Trio x y z) -> (x,y,z)) list =| n |= (list :: [(Int,Int,Int)])
, map peanoToNat list =| n |= list
, map listLst list =| n |= (list :: [[Bool]])
, map listLst list =| n |= (list :: [[Int]])
, mapT peanoToNat tiers =| 6 |= tiers
, mapT listLst tiers =| 6 |= (tiers :: [[ [Bool] ]])
, mapT listLst tiers =| 6 |= (tiers :: [[ [Int] ]])
, (tiers :: [[ Bool ]]) =| 6 |= $(deriveTiers ''Bool)
, (tiers :: [[ [Int] ]]) =| 6 |= $(deriveTiers ''[])
, (tiers :: [[ [Bool] ]]) =| 6 |= $(deriveTiers ''[])
, (tiers :: [[ Maybe Int ]]) =| 6 |= $(deriveTiers ''Maybe)
, (tiers :: [[ Maybe Bool ]]) =| 6 |= $(deriveTiers ''Maybe)
, (tiers :: [[Either Bool Int]])
=$ map sort . take 6 $= $(deriveTiers ''Either)
, (list :: [ Bool ]) =| n |= $(deriveList ''Bool)
, (list :: [ [Int] ]) =| n |= $(deriveList ''[])
, (list :: [ [Bool] ]) =| n |= $(deriveList ''[])
, (list :: [ Maybe Int ]) =| n |= $(deriveList ''Maybe)
, (list :: [ Maybe Bool ]) =| n |= $(deriveList ''Maybe)
, map length (take 6 $ tiers :: [[Unit]]) == [1]
, map length (take 6 $ tiers :: [[Novel Peano]]) == [1,1,1,1,1,1]
, map length (take 6 $ tiers :: [[Duo Peano Peano]]) == [1,2,3,4,5,6]
, map length (take 6 $ tiers :: [[Trio Int Int Int]]) == [1,3,6,10,15,21]
, map length (take 6 $ tiers :: [[Novel Choice]]) == [2]
, map length (take 6 $ tiers :: [[Duo Choice Choice]]) == [4]
, map length (take 6 $ tiers :: [[Trio Choice Choice Choice]]) == [8]
, map length (take 6 $ tiers :: [[ [Novel Int] ]]) == [1,1,2,4,8,16]
, map length (take 6 $ tiers :: [[ [Novel Bool] ]]) == [1,2,4,8,16,32]
, map length (take 6 $ tiers :: [[ [Duo Int Int] ]]) == [1,1,3,8,21,55]
, map length (take 6 $ tiers :: [[ Lst Int ]]) == [1,1,2,4,8,16]
, map length (take 6 $ tiers :: [[ Lst Bool ]]) == [1,2,4,8,16,32]
, map length (take 6 $ tiers :: [[ Mutual ]]) == [1,1,1,1,1,1]
, map length (take 6 $ tiers :: [[ Nouter ]]) == [1]
, map length (take 6 $ tiers :: [[ Outer ]]) == [1]
, map length (take 6 $ tiers :: [[ Inner ]]) == [1]
]
peanoToNat :: Peano -> Nat
peanoToNat Zero = 0
peanoToNat (Succ n) = 1 + peanoToNat n
listLst :: Lst a -> [a]
listLst Nil = []
listLst (x :- xs) = x : listLst xs