diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,58 +11,66 @@
   build-and-test:
     runs-on: ubuntu-latest
     steps:
+      - run: git   --version
+      - run: make  --version
+      - run: ghc   --version
+      - run: cabal --version
 
-      - name: Cache ~/.cabal/packages
+      - name: Check out repository
+        uses: actions/checkout@v3
+
+      # check out needs to happen before cache so that hashing works
+      - name: Cache hash
+        run: echo Cache hash = ${{ hashFiles('*.cabal') }}
+
+      - name: Cache cabal (source) packages
         uses: actions/cache@v3
         with:
-          path: ~/.cabal/packages
+          path: |
+            ~/.cabal/packages
+            ~/.cache/cabal
           key:          v1-${{ runner.os }}-cabal-packages-${{ hashFiles('*.cabal') }}
           restore-keys: v1-${{ runner.os }}-cabal-packages-
 
-      - name: Cache ~/.cabal and ~/.ghc
+      - name: Cache installed cabal packages
         uses: actions/cache@v3
         with:
           path: |
             ~/.cabal
             !~/.cabal/packages
+            ~/.config/cabal
+            ~/.local/state/cabal
             ~/.ghc
           key:          v1-${{ runner.os }}-cabal-ghc-latest-${{ hashFiles('*.cabal') }}
-          restore-keys: v1-${{ runner.os }}-cabal-ghc-latest-
-
-      - run: du -hd3 ~/.cabal ~/.ghc || true
-
-      - run: make --version
+          restore-keys: v1-${{ runner.os }}-cabal-ghc-latest-${{ hashFiles('*.cabal') }}
+          # restore with exact match has some versions of cabal have trouble updating
 
       - run: haddock --version || sudo apt-get install ghc-haddock
-      - run: ghc     --version
-      - run: cabal   --version
-      - run: haddock --version
-      - run: ghc-pkg list
-
-      - name: Check out repository
-        uses: actions/checkout@v3
+      # blank line
+      # blank line for alignment with matrix scripts
 
-      - run: git --version
+      - run: du -hd3 ~/.ghc ~/.cabal ~/.config/cabal ~/.cache/cabal ~/.local/state/cabal || true
 
+      - run: ghc-pkg list
       - run: make install-dependencies
+      - run: ghc-pkg list
 
-      # 2023-07: some projects were failing with missing base for GHC 9.6.
-      #          Here we compile through cabal only provisionally.
-      # - run: make
-      # - run: make test
-      # - run: make haddock
+      - run: du -hd3 ~/.ghc ~/.cabal ~/.config/cabal ~/.cache/cabal ~/.local/state/cabal || true
+
+      - run: make
+      - run: make test
+      - run: make haddock
       - run: make test-sdist
-      #- run: make test-via-cabal
-      - run: cabal configure --enable-tests --enable-benchmarks --ghc-options="-O0"
-      - run: cabal build
-      - run: cabal test
-      - run: cabal haddock
+      - run: make test-via-cabal
 
 
   test-with-ghc:
     strategy:
+      max-parallel: 6
       matrix:
+        # starting with 9.10, docker/_/haskell requires -bullseye as suffix
         ghc:
+          - '9.10-bullseye'
           - '9.8'
           - '9.6'
           - '9.4'
@@ -70,47 +78,56 @@
           - '9.0'
           - '8.10'
           - '8.8'
-          - '8.6'
-          - '8.4'
-          - '8.2'
-          - '7.10'
     runs-on: ubuntu-latest
     needs: build-and-test
     container: haskell:${{ matrix.ghc }}
     steps:
-      - name: Cache ~/.cabal/packages
+      - run: git   --version || true # git is missing in some images
+      - run: make  --version || true # make is missing in some images
+      - run: ghc   --version
+      - run: cabal --version
+
+      - name: Check out repository
+        uses: actions/checkout@v3
+
+      # check out needs to happen before cache so that hashing works
+      - name: Cache hash
+        run: echo Cache hash = ${{ hashFiles('*.cabal') }}
+
+      - name: Cache cabal (source) packages
         uses: actions/cache@v3
         with:
-          path: ~/.cabal/packages
+          path: |
+            ~/.cabal/packages
+            ~/.cache/cabal
           key:          v1-${{ runner.os }}-cabal-packages-${{ hashFiles('*.cabal') }}
           restore-keys: v1-${{ runner.os }}-cabal-packages-
 
-      - name: Cache ~/.cabal and ~/.ghc
+      - name: Cache installed cabal packages
         uses: actions/cache@v3
         with:
           path: |
             ~/.cabal
             !~/.cabal/packages
+            ~/.config/cabal
+            ~/.local/state/cabal
             ~/.ghc
           key:          v1-${{ runner.os }}-cabal-ghc-${{ matrix.ghc }}-${{ hashFiles('*.cabal') }}
-          restore-keys: v1-${{ runner.os }}-cabal-ghc-${{ matrix.ghc }}-
-
-      - run: du -hd3 ~/.cabal ~/.ghc || true
+          restore-keys: v1-${{ runner.os }}-cabal-ghc-${{ matrix.ghc }}-${{ hashFiles('*.cabal') }}
+          # restore with exact match has some versions of cabal have trouble updating
 
       - run: make --version || rm /etc/apt/sources.list.d/*.list # faster update
       - run: make --version || apt-get update
       - run: make --version || apt-get install make
 
-      - run: ghc     --version
-      - run: cabal   --version
-      - run: haddock --version
-      - run: ghc-pkg list
-
-      - name: Check out repository
-        uses: actions/checkout@v3
+      - run: du -hd3 ~/.ghc ~/.cabal ~/.config/cabal ~/.cache/cabal ~/.local/state/cabal || true
 
+      - run: ghc-pkg list
       - run: make install-dependencies
+      - run: ghc-pkg list
 
+      - run: du -hd3 ~/.ghc ~/.cabal ~/.config/cabal ~/.cache/cabal ~/.local/state/cabal || true
+
       - run: make
       - run: make test
       - run: make haddock
@@ -121,23 +138,44 @@
     runs-on: ubuntu-latest
     needs: build-and-test
     steps:
-      - name: Setup Haskell's GHC and Cabal as required by current Stackage LTS
-        uses: haskell-actions/setup@v2
-        with: # lts-19.19
-          ghc-version: '9.0.2'
-          cabal-version: '3.4'
+      - name: Check out repository
+        uses: actions/checkout@v3
 
-      - uses: actions/cache@v3
+      # check out needs to happen before cache so that hashing works
+      - name: Cache hash
+        run: echo Cache hash = ${{ hashFiles('stack.yaml') }}
+
+      - name: Cache stack folder
+        uses: actions/cache@v3
         with:
           path: ~/.stack
           key:          v1-${{ runner.os }}-stack-${{ hashFiles('stack.yaml') }}
           restore-keys: v1-${{ runner.os }}-stack-
 
+      - name: Cache ghcup folder
+        uses: actions/cache@v3
+        with:
+          path: |
+            ~/.ghcup
+            /usr/local/.ghcup/bin
+            /usr/local/.ghcup/db
+            /usr/local/.ghcup/ghc/9.4.8
+          key:          v1-${{ runner.os }}-ghcup-${{ hashFiles('stack.yaml') }}
+          restore-keys: v1-${{ runner.os }}-ghcup-
+
+      - name: Setup Haskell's GHC and Cabal as required by current Stackage LTS
+        uses: haskell-actions/setup@v2
+        with: # lts-21.25
+          ghc-version: '9.4.8'
+          cabal-version: '3.8'
+
+      - run: du -hd2 ~/.stack ~/.ghcup /usr/local/.ghcup || true
+
       - run: stack --version
 
-      - name: Check out repository
-        uses: actions/checkout@v3
       - run: make test-via-stack
+
+      - run: du -hd2 ~/.stack ~/.ghcup /usr/local/.ghcup || true
 
   test-with-hugs:
     runs-on: ubuntu-latest
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -101,6 +101,7 @@
 	./test/sdist
 
 test-via-cabal:
+	cabal update # recent (2024) cabal refuses to build without a package list
 	cabal configure --enable-tests --enable-benchmarks --ghc-options="$(GHCFLAGS) -O0"
 	cabal build
 	cabal test main
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -2,6 +2,13 @@
 =======================
 
 
+v1.0.4 (August 2025)
+--------------------
+
+* `Test.LeanCheck.Derive.deriveListable`: avoid empty tiers when possible
+* minor Haddock documentation improvements
+
+
 v1.0.2 (January 2024)
 ---------------------
 
diff --git a/leancheck.cabal b/leancheck.cabal
--- a/leancheck.cabal
+++ b/leancheck.cabal
@@ -11,7 +11,7 @@
 -- this cabal file too complicated.  -- Rudy
 
 name:                leancheck
-version:             1.0.2
+version:             1.0.4
 synopsis:            Enumerative property-based testing
 description:
   LeanCheck is a simple enumerative property-based testing library.
@@ -70,7 +70,8 @@
                   , mk/install-on
                   , stack.yaml
                   , test/sdist
-tested-with: GHC==9.8
+tested-with: GHC==9.10
+           , GHC==9.8
            , GHC==9.6
            , GHC==9.4
            , GHC==9.2
@@ -81,6 +82,7 @@
            , GHC==8.4
            , GHC==8.2
            , GHC==7.10
+           , GHC==7.8
            , Hugs==2006.9
 
 source-repository head
@@ -90,7 +92,7 @@
 source-repository this
   type:            git
   location:        https://github.com/rudymatela/leancheck
-  tag:             v1.0.2
+  tag:             v1.0.4
 
 library
   exposed-modules: Test.LeanCheck
diff --git a/mk/haskell.mk b/mk/haskell.mk
--- a/mk/haskell.mk
+++ b/mk/haskell.mk
@@ -91,9 +91,14 @@
 
 install-dependencies:
 	if [ -n "$(INSTALL_DEPS)" ]; then \
+		cd ~ && \
 		cabal update && \
-		$(CABAL_INSTALL) $(INSTALL_DEPS); \
+		$(CABAL_INSTALL) $(INSTALL_DEPS) || true; \
 	fi
+	# above, "|| true" is needed for cabal >= 3.10.2
+	# Before, cabal would successfully skip installation
+	#         of already existing packages
+	# cd ~ is needed so cabal installs only dependencies
 
 # haddock rules
 haddock: doc/index.html
diff --git a/src/Test/LeanCheck/Basic.hs b/src/Test/LeanCheck/Basic.hs
--- a/src/Test/LeanCheck/Basic.hs
+++ b/src/Test/LeanCheck/Basic.hs
@@ -15,12 +15,12 @@
 --   * a 'Listable' 'Word' instance;
 --   * a 'Listable' 'Ratio' instance (consequently 'Listable' 'Rational');
 --   * a 'Listable' 'Complex' instance;
---   * 'Listable' 'Int8/16/32/64' instances;
---   * 'Listable' 'Word8/16/32/64' instances;
+--   * 'Listable' 'Int8', 'Int16', 'Int32' and 'Int64' instances;
+--   * 'Listable' 'Word8', 'Word16', 'Word32' and 'Word64' instances;
 --   * 'Listable' instances for "Foreign.C" types;
 --   * a 'Listable' 'ExitCode' instance;
 --   * a 'Listable' 'GeneralCategory' instance;
---   * 'Listable' 'Buffer/IO/SeekMode' instances;
+--   * 'Listable' 'Buffer', 'IO' and 'SeekMode' instances;
 --   * the operators 'addWeight' and 'ofWeight'.
 --
 -- The above includes all types defined in the Haskell 2010 Report
diff --git a/src/Test/LeanCheck/Derive.hs b/src/Test/LeanCheck/Derive.hs
--- a/src/Test/LeanCheck/Derive.hs
+++ b/src/Test/LeanCheck/Derive.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE TemplateHaskell, CPP #-}
 -- |
 -- Module      : Test.LeanCheck.Derive
--- Copyright   : (c) 2015-2024 Rudy Matela
+-- Copyright   : (c) 2015-2025 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
@@ -144,12 +144,25 @@
 -- > instance Listable MyType where
 -- >   tiers  =  $(deriveTiers)
 deriveTiers :: Name -> ExpQ
-deriveTiers t  =  conse =<< typeConstructors t
+deriveTiers t  =  conse =<< typeConstructorsWithArityAndRecursiveness t
   where
-  cone n as  =  do
-    (Just consN) <- lookupValueName $ "cons" ++ show (length as)
-    [| $(varE consN) $(conE n) |]
-  conse  =  foldr1 (\e1 e2 -> [| $e1 \/ $e2 |]) . map (uncurry cone)
+  cone (n,arity,shouldReset) =  do
+    (Just consN) <- lookupValueName $ "cons" ++ show arity
+    -- the shouldReset switch is necessary to avoid derivations
+    -- where we end with an empty tier at the head of the tiers list
+    -- such as a type homomorphic to Either
+    -- on earlier LeanCheck versions, we never reset
+    if shouldReset
+    then [| reset ($(varE consN) $(conE n)) |]
+    else [|        $(varE consN) $(conE n)  |]
+  conse  =  foldr1 (\e1 e2 -> [| $e1 \/ $e2 |]) . map cone . arityReset
+  -- computes whether we should reset some constructors and which
+  arityReset nars
+    -- if there's a constructor with 0 arguments, we don't need to reset
+    | or [arity == 0 | (_,arity,_) <- nars]  =  [(name,arity,False) | (name,arity,_) <- nars]
+    -- otherwise we reset constructors that are not recursive to avoid infinite loops
+    | otherwise  =  [(name, arity, arity > 0 && not isRecursive) | (name,arity,isRecursive) <- nars]
+    -- by reset here of course we mean removing the preceding empty tiers
 
 -- | Given a type 'Name', derives an expression to be placed as the result of
 --   'list':
@@ -174,22 +187,29 @@
 typeConArgs t  =  do
   is <- isTypeSynonym t
   if is
-  then typeConTs `fmap` typeSynonymType t
-  else (nubMerges . map typeConTs . concatMap snd) `fmap` typeConstructors t
-  where
-  typeConTs :: Type -> [Name]
-  typeConTs (AppT t1 t2)  =  typeConTs t1 `nubMerge` typeConTs t2
-  typeConTs (SigT t _)  =  typeConTs t
-  typeConTs (VarT _)  =  []
-  typeConTs (ConT n)  =  [n]
+  then subtypeNames `fmap` typeSynonymType t
+  else (nubMerges . map subtypeNames . concatMap snd) `fmap` typeConstructors t
+
+subtypeNames :: Type -> [Name]
+subtypeNames (AppT t1 t2)  =  subtypeNames t1 `nubMerge` subtypeNames t2
+subtypeNames (SigT t _)  =  subtypeNames t
+subtypeNames (VarT _)  =  []
+subtypeNames (ConT n)  =  [n]
 #if __GLASGOW_HASKELL__ >= 800
-  -- typeConTs (PromotedT n)  =  [n] ?
-  typeConTs (InfixT  t1 n t2)  =  typeConTs t1 `nubMerge` typeConTs t2
-  typeConTs (UInfixT t1 n t2)  =  typeConTs t1 `nubMerge` typeConTs t2
-  typeConTs (ParensT t)  =  typeConTs t
+-- subtypeNames (PromotedT n)  =  [n] ?
+subtypeNames (InfixT  t1 n t2)  =  subtypeNames t1 `nubMerge` subtypeNames t2
+subtypeNames (UInfixT t1 n t2)  =  subtypeNames t1 `nubMerge` subtypeNames t2
+subtypeNames (ParensT t)  =  subtypeNames t
 #endif
-  typeConTs _  =  []
+subtypeNames _  =  []
 
+cascadingSubtypeNames :: [Type] -> Q [Name]
+cascadingSubtypeNames t  =  do
+  nss <- mapM (`typeConCascadingArgsThat` (\t -> return $ t `notElem` ns)) ns
+  return $ nubMerges (ns:nss)
+  where
+  ns  =  nubMerges $ map subtypeNames t
+
 typeConArgsThat :: Name -> (Name -> Q Bool) -> Q [Name]
 t `typeConArgsThat` p  =  filterM p =<< typeConArgs t
 
@@ -308,6 +328,7 @@
 -- paired with the type arguments they take.
 -- the type arguments they take.
 --
+-- > > :set -XTemplateHaskell
 -- > > putStrLn $(stringE . show =<< typeConstructors ''Bool)
 -- > [ ('False, [])
 -- > , ('True, [])
@@ -334,14 +355,41 @@
   cons (TyConI (DataD    _ _ _ _ cs _))  =  cs
   cons (TyConI (NewtypeD _ _ _ _ c  _))  =  [c]
 #endif
-  cons _  =  errorOn "typeConstructors"
-          $  "neither newtype nor data: " ++ show t
+  cons _  =  []
   normalize (NormalC n ts)   =  (n,map snd ts)
   normalize (RecC    n ts)   =  (n,map trd ts)
   normalize (InfixC  t1 n t2)  =  (n,[snd t1,snd t2])
   normalize _  =  errorOn "typeConstructors"
                $  "unexpected unhandled case when called with " ++ show t
   trd (x,y,z)  =  z
+
+-- |
+-- Given a type 'Name',
+-- returns a list of its type constructors 'Name's
+-- tupled with its arity and whether the constructor is recursive.
+--
+-- > > :set -XTemplateHaskell
+-- > > data Lst a  =  a :- Lst a | Nil  deriving Show
+-- > > putStrLn $(stringE . show =<< typeConstructorsWithArityAndRecursiveness ''Lst)
+-- > [ ('(:-),2,True)
+-- > , ('Nil,0,False)
+-- > ]
+--
+-- The recursive item does not work properly for some built-in types such as list
+-- as they have special representations within TH.
+--
+-- > > putStrLn $(stringE . show =<< typeConstructorsWithArityAndRecursiveness ''[])
+-- > [ ('[],0,False)
+-- > , ('(:),2,False)
+-- > ]
+typeConstructorsWithArityAndRecursiveness :: Name -> Q [(Name,Int,Bool)]
+typeConstructorsWithArityAndRecursiveness t  =  do
+  cs <- typeConstructors t
+  mapM ar cs
+  where
+  ar (n,ts)  =  do
+    ns <- cascadingSubtypeNames ts
+    return (n, length ts, t `elem` ns)
 
 -- |
 -- Is the given 'Name' a type synonym?
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,4 +1,4 @@
-resolver: lts-19.19 # or ghc-9.0.2
+resolver: lts-21.25 # or ghc-9.4.8
 
 packages:
 - .
diff --git a/test/derive.hs b/test/derive.hs
--- a/test/derive.hs
+++ b/test/derive.hs
@@ -1,66 +1,73 @@
--- Copyright (c) 2015-2024 Rudy Matela.
+-- 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)
-
-data D0        =  D0                     deriving Show
-newtype D1 a   =  D1 a                   deriving Show
-data D2 a b    =  D2 a b                 deriving Show
-data D3 a b c  =  D3 a b c               deriving Show
-data C1 a      =            C11 a | C10  deriving Show
-data C2 a b    =  C22 a b | C21 a | C20  deriving Show
-data I a b     =  a :+ b                 deriving Show
+import Data.List (sort, isPrefixOf)
 
-deriveListable ''D0
-deriveListable ''D1
-deriveListable ''D2
-deriveListable ''D3
-deriveListable ''C1
-deriveListable ''C2
-deriveListable ''I
+-- 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)
 
--- recursive datatypes
-data Peano  =  Zero | Succ Peano  deriving Show
-data List a  =  a :- List a | Nil  deriving Show
-data Bush a  =  Bush a :-: Bush a | Leaf a  deriving (Show, Eq)
-data Tree a  =  Node (Tree a) a (Tree a) | Null  deriving (Show, Eq)
+infixr 5 :-
 
 deriveListable ''Peano
-deriveListable ''List
-deriveListable ''Bush
+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
 
--- Nested datatype cascade
+-- 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
 
--- Recursive nested datatype cascade
+-- 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
 
--- Type synonyms
-data Pair a  =  Pair a a
-type Alias a  =  Pair a
--- deriveListable ''Alias -- this will fail
-deriveListableCascading ''Alias
-deriveListableIfNeeded ''Alias -- only works because instance already exists
-
--- Nested type synonyms
-data Triple a  =  Triple a a a
-type Tralias a  =  Triple a
-data Pairiple a  =  Pairriple (Tralias a) (Tralias a)
-deriveListableCascading ''Pairiple
-
 -- Those should have no effect (instance already exists):
 {- uncommenting those should generate warnings
 deriveListable ''Bool
@@ -80,51 +87,113 @@
 tests n  =
   [ True
 
-  , map unD0 list =| n |= list
-  , map unD1 list =| n |= (list :: [Int])
-  , map unD2 list =| n |= (list :: [(Int,Int)])
-  , map unD3 list =| n |= (list :: [(Int,Int,Int)])
+  , [ Zero
+    , Succ Zero
+    , Succ (Succ Zero)
+    , Succ (Succ (Succ Zero))
+    ] `isPrefixOf` list
 
-  , map unD1 list == (list :: [()])
-  , map unD2 list == (list :: [((),())])
-  , map unD3 list == (list :: [((),(),())])
+  , [Yes, No] == list
 
-  , map unD1 list == (list :: [Bool])
-  , map unD2 list == (list :: [(Bool,Bool)])
-  , map unD3 list == (list :: [(Bool,Bool,Bool)])
+  , [ Nil
+    , Unit :- Nil
+    , Unit :- Unit :- Nil
+    , Unit :- Unit :- Unit :- Nil
+    ] `isPrefixOf` list
 
-  , map peanoToNat list =| n |= list
-  , map listToList list =| n |= (list :: [[Bool]])
-  , map listToList list =| n |= (list :: [[Int]])
+  , [ Nil
+    , Zero :- Nil
+    , Zero :- (Zero :- Nil)
+    , Succ Zero :- Nil
+    , Zero :- (Zero :- (Zero :- Nil))
+    , Zero :- (Succ Zero :- Nil)
+    ] `isPrefixOf` list
 
-  , mapT peanoToNat tiers =| 6 |= tiers
-  , mapT listToList tiers =| 6 |= (tiers :: [[ [Bool] ]])
-  , mapT listToList tiers =| 6 |= (tiers :: [[ [Int] ]])
+  , list == [Yes :+ Yes, Yes :+ No, No :+ Yes, No :+ No]
 
-  , take 6 (list :: [Bush Bool])
-    == [ Leaf False
-       , Leaf True
-       , Leaf False :-: Leaf False
-       , Leaf False :-: Leaf True
-       , Leaf True :-: Leaf False
-       , Leaf True :-: Leaf True
-       ]
+  , [ Zero :+ Zero
+    , Zero :+ Succ Zero
+    , Succ Zero :+ Zero
+    , Zero :+ Succ (Succ Zero)
+    , Succ Zero :+ Succ Zero
+    ] `isPrefixOf` list
 
-  , take 6 (list :: [Tree Bool])
-    == [ 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)
-       ]
+  , 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]])
+  , (tiers :: [[Either Bool Int]])
     =$ map sort . take 6 $= $(deriveTiers ''Either)
 
   , (list :: [ Bool       ]) =| n |= $(deriveList ''Bool)
@@ -132,17 +201,32 @@
   , (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]
   ]
-  where
-  unD0 (D0)        =  ()
-  unD1 (D1 x)      =  (x)
-  unD2 (D2 x y)    =  (x,y)
-  unD3 (D3 x y z)  =  (x,y,z)
 
 peanoToNat :: Peano -> Nat
 peanoToNat Zero  =  0
 peanoToNat (Succ n)  =  1 + peanoToNat n
 
-listToList :: List a -> [a]
-listToList Nil  =  []
-listToList (x :- xs)  =  x : listToList xs
+listLst :: Lst a -> [a]
+listLst Nil  =  []
+listLst (x :- xs)  =  x : listLst xs
diff --git a/test/generic.hs b/test/generic.hs
--- a/test/generic.hs
+++ b/test/generic.hs
@@ -6,45 +6,59 @@
 import Test.LeanCheck.Generic
 import Test.LeanCheck.Derive (deriveTiers)
 import Test.LeanCheck.Utils
-import Data.List (sort)
+import Data.List (sort, isPrefixOf)
 import GHC.Generics (Generic)
 
-data D0        =  D0                     deriving (Eq, Show, Generic)
-newtype D1 a   =  D1 a                   deriving (Eq, Show, Generic)
-data D2 a b    =  D2 a b                 deriving (Eq, Show, Generic)
-data D3 a b c  =  D3 a b c               deriving (Eq, Show, Generic)
-data C1 a      =            C11 a | C10  deriving (Eq, Show, Generic)
-data C2 a b    =  C22 a b | C21 a | C20  deriving (Eq, Show, Generic)
-data I a b     =  a :+ b                 deriving (Eq, Show, Generic)
+-- 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, Generic)
+data  Choice  =  Yes | No  deriving (Eq, Ord, Show, Generic)
+data  Lst a  =  a :- Lst a | Nil  deriving (Eq, Ord, Show, Generic)
+data  Duo a b  =  a :+ b  deriving (Eq, Ord, Show, Generic)
+data  Unit  =  Unit  deriving (Eq, Ord, Show, Generic)
+data  Perhaps a  =  Naught | Precisely a  deriving (Eq, Ord, Show, Generic)
+data  Alternatively a b  =  Sinister a | Dexter b  deriving (Eq, Ord, Show, Generic)
+data  Relation  =  Smaller | Same | Bigger  deriving (Eq, Ord, Show, Generic)
+data  Trio a b c  =  Trio a b c  deriving (Eq, Ord, Show, Generic)
 
-instance Listable D0                   where  tiers  =  genericTiers
+infixr 5 :-
 
-instance Listable a => Listable (D1 a) where  tiers  =  genericTiers
+instance Listable Peano where tiers = genericTiers
+instance Listable Choice where tiers = genericTiers
+instance Listable a => Listable (Lst a) where tiers = genericTiers
+instance (Listable a, Listable b) => Listable (Duo a b) where tiers = genericTiers
+instance Listable Unit where tiers = genericTiers
+instance Listable a => Listable (Perhaps a) where tiers = genericTiers
+instance (Listable a, Listable b) => Listable (Alternatively a b) where tiers = genericTiers
+instance Listable Relation where tiers = genericTiers
+instance (Listable a, Listable b, Listable c) => Listable (Trio a b c) where tiers = genericTiers
 
-instance (Listable a, Listable b)
-      => Listable (D2 a b)             where  tiers  =  genericTiers
 
-instance (Listable a, Listable b, Listable c)
-      => Listable (D3 a b c)           where  tiers  =  genericTiers
+-- recursive datatypes
+data Tree a  =  Node (Tree a) a (Tree a) | Null  deriving (Show, Eq, Generic)
+data Bush a  =  Bush a :-: Bush a | Leaf a  deriving (Show, Eq, Generic)
 
-instance Listable a => Listable (C1 a) where  tiers  =  genericTiers
+instance Listable a => Listable (Tree a) where tiers = genericTiers
+instance Listable a => Listable (Bush a) where tiers = genericTiers
 
-instance (Listable a, Listable b)
-      => Listable (C2 a b)             where  tiers  =  genericTiers
+-- mutually recursive types
+data Mutual    =  Munil | Mutual CoMutual  deriving (Eq, Ord, Show, Generic)
+data CoMutual  =  CoMunil | CoMutual Mutual  deriving (Eq, Ord, Show, Generic)
 
-instance (Listable a, Listable b)
-      => Listable (I a b)              where  tiers  =  genericTiers
+instance Listable Mutual where tiers = genericTiers
+instance Listable CoMutual where tiers = genericTiers
 
--- recursive datatypes
-data Peano  =  Zero | Succ Peano  deriving (Show, Generic)
-data List a  =  a :- List a | Nil  deriving (Show, Generic)
-data Bush a  =  Bush a :-: Bush a | Leaf a  deriving (Show, Eq, Generic)
-data Tree a  =  Node (Tree a) a (Tree a) | Null  deriving (Show, Eq, Generic)
+-- newtypes, type synonyms, inner/outer
+newtype  Novel a  =  Novel a  deriving (Eq, Ord, Show, Generic)
+data  Inner  =  I  deriving (Eq, Ord, Show, Generic)
+data  Outer  =  O Inner  deriving (Eq, Ord, Show, Generic)
+type  Nouter  =  Novel Outer
 
-instance Listable Peano where  tiers  =  genericTiers
-instance Listable a => Listable (List a) where  tiers  =  genericTiers
-instance Listable a => Listable (Bush a) where  tiers  =  genericTiers
-instance Listable a => Listable (Tree a) where  tiers  =  genericTiers
+instance Listable a => Listable (Novel a) where tiers = genericTiers
+instance Listable Inner where tiers = genericTiers
+instance Listable Outer where tiers = genericTiers
 
 
 main :: IO ()
@@ -54,26 +68,106 @@
 tests n  =
   [ True
 
-  , map unD0 list =| n |= list
-  , map unD1 list =| n |= (list :: [Int])
-  , map unD2 list =| n |= (list :: [(Int,Int)])
-  , map unD3 list =| n |= (list :: [(Int,Int,Int)])
+  , [ Zero
+    , Succ Zero
+    , Succ (Succ Zero)
+    , Succ (Succ (Succ Zero))
+    ] `isPrefixOf` list
 
-  , map unD1 list == (list :: [()])
-  , map unD2 list == (list :: [((),())])
-  , map unD3 list == (list :: [((),(),())])
+  , [Yes, No] == list
 
-  , map unD1 list == (list :: [Bool])
-  , map unD2 list == (list :: [(Bool,Bool)])
-  , map unD3 list == (list :: [(Bool,Bool,Bool)])
+  , [ 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 listToList list =| n |= (list :: [[Bool]])
-  , map listToList list =| n |= (list :: [[Int]])
+  , map listLst list =| n |= (list :: [[Bool]])
+  , map listLst list =| n |= (list :: [[Int]])
 
   , mapT peanoToNat tiers =| 6 |= tiers
-  , mapT listToList tiers =| 6 |= (tiers :: [[ [Bool] ]])
-  , mapT listToList tiers =| 6 |= (tiers :: [[ [Int] ]])
+  , mapT listLst tiers =| 6 |= (tiers :: [[ [Bool] ]])
+  , mapT listLst tiers =| 6 |= (tiers :: [[ [Int] ]])
 
   , take 6 (list :: [Bush Bool])
     == [ Leaf False
@@ -112,18 +206,13 @@
   , (genericTiers :: [[ [Bool]     ]])       =| 6 |=  $(deriveTiers ''[])
   , (genericTiers :: [[ Maybe Int  ]])       =| 6 |=  $(deriveTiers ''Maybe)
   , (genericTiers :: [[ Maybe Bool ]])       =| 6 |=  $(deriveTiers ''Maybe)
-  , (genericTiers :: [[ Either Bool Int ]])  =| 6 |=  $(deriveTiers ''Either)
+  , (genericTiers :: [[ Either Bool Int ]])  =| 6 |=  ([] : $(deriveTiers ''Either))
   ]
-  where
-  unD0 (D0)        =  ()
-  unD1 (D1 x)      =  (x)
-  unD2 (D2 x y)    =  (x,y)
-  unD3 (D3 x y z)  =  (x,y,z)
 
 peanoToNat :: Peano -> Nat
 peanoToNat Zero  =  0
 peanoToNat (Succ n)  =  1 + peanoToNat n
 
-listToList :: List a -> [a]
-listToList Nil  =  []
-listToList (x :- xs)  =  x : listToList xs
+listLst :: Lst a -> [a]
+listLst Nil  =  []
+listLst (x :- xs)  =  x : listLst xs
