diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
 # .travis.yml file for Express
 #
-# Copyright:   (c) 2017-2020 Rudy Matela
+# Copyright:   (c) 2017-2021 Rudy Matela
 # License:     3-Clause BSD  (see the file LICENSE)
 # Maintainer:  Rudy Matela <rudy@matela.com.br>
 
@@ -48,11 +48,17 @@
   - ghc: 'head'
   include:
   - ghc: 'head'
-    env:                   GHCVER=head         CABALVER=head   STACKVER=nightly-2020-03-28
-    addons: {apt: {packages: [ghc-head,   cabal-install-head], sources: hvr-ghc}}
+    env:                   GHCVER=head        CABALVER=head    STACKVER=nightly-2021-04-06
+    addons: {apt: {packages: [ghc-head,  cabal-install-head],  sources: hvr-ghc}}
+  - ghc: '9.0'
+    env:                   GHCVER=9.0.1       CABALVER=head    STACKVER=nightly-2021-04-06
+    addons: {apt: {packages: [ghc-9.0.1, cabal-install-head],  sources: hvr-ghc}}
+  - ghc: '8.10'
+    env:                   GHCVER=8.10.4       CABALVER=3.2    STACKVER=lts-17.9
+    addons: {apt: {packages: [ghc-8.10.4, cabal-install-3.2],  sources: hvr-ghc}}
   - ghc: '8.8'
-    env:                   GHCVER=8.8.3        CABALVER=3.0    STACKVER=lts-15.5
-    addons: {apt: {packages: [ghc-8.8.3,  cabal-install-3.0],  sources: hvr-ghc}}
+    env:                   GHCVER=8.8.4        CABALVER=3.0    STACKVER=lts-16.31
+    addons: {apt: {packages: [ghc-8.8.4,  cabal-install-3.0],  sources: hvr-ghc}}
   - ghc: '8.6'
     env:                   GHCVER=8.6.5        CABALVER=2.4    STACKVER=lts-14.27
     addons: {apt: {packages: [ghc-8.6.5,  cabal-install-2.4],  sources: hvr-ghc}}
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2019-2020, Rudy Matela
+Copyright (c) 2019-2021, Rudy Matela
 
 All rights reserved.
 
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 # Makefile for express
 #
-# Copyright:   (c) 2015-2018 Rudy Matela
+# Copyright:   (c) 2015-2021 Rudy Matela
 # License:     3-Clause BSD  (see the file LICENSE)
 # Maintainer:  Rudy Matela <rudy@matela.com.br>
 TESTS = \
@@ -89,14 +89,20 @@
 
 test-via-everything: test test-via-cabal test-via-stack
 
-legacy-test: # needs ghc-8.0 .. ghc-7.8 installed as such
-	make clean  &&  make test GHC=ghc-8.2  GHCFLAGS="-Werror -dynamic"
-	make clean  &&  make test GHC=ghc-8.0  GHCFLAGS="-Werror -dynamic"
-	make clean  &&  make test GHC=ghc-7.10 GHCFLAGS="-Werror -dynamic"
-	make clean  &&  make test GHC=ghc-7.8  GHCFLAGS="-Werror -dynamic"
-	make clean  &&  make test
+legacy-test: # needs ghc-8.8 .. ghc-7.8 installed as such
+	make clean  &&  make test -j GHC=ghc-8.8
+	make clean  &&  make test -j GHC=ghc-8.6
+	make clean  &&  make test -j GHC=ghc-8.4
+	make clean  &&  make test -j GHC=ghc-8.2
+	make clean  &&  make test -j GHC=ghc-8.0
+	make clean  &&  make test -j GHC=ghc-7.10
+	make clean  &&  make test -j GHC=ghc-7.8
+	make clean  &&  make test -j
 
 legacy-test-via-cabal: # needs similarly named cabal wrappers
+	cabal clean  &&  cabal-ghc-8.8  configure  &&  cabal-ghc-8.8  test
+	cabal clean  &&  cabal-ghc-8.6  configure  &&  cabal-ghc-8.6  test
+	cabal clean  &&  cabal-ghc-8.4  configure  &&  cabal-ghc-8.4  test
 	cabal clean  &&  cabal-ghc-8.2  configure  &&  cabal-ghc-8.2  test
 	cabal clean  &&  cabal-ghc-8.0  configure  &&  cabal-ghc-8.0  test
 	cabal clean  &&  cabal-ghc-7.10 configure  &&  cabal-ghc-7.10 test
@@ -104,13 +110,19 @@
 	cabal clean  &&  cabal test
 
 prepare:
-	cabal update  &&  cabal install leancheck
+	cabal update
+	cabal install $(ALL_DEPS) --lib
 
 prepare-legacy-test:
-	cabal-ghc-8.2  update  &&  cabal-ghc-8.2  install leancheck
-	cabal-ghc-8.0  update  &&  cabal-ghc-8.0  install leancheck
-	cabal-ghc-7.10 update  &&  cabal-ghc-7.10 install leancheck
-	cabal-ghc-7.8  update  &&  cabal-ghc-7.8  install leancheck
+	cabal update
+	cabal-ghc-8.8  install $(ALL_DEPS) --lib
+	cabal-ghc-8.6  install $(ALL_DEPS) --lib
+	cabal-ghc-8.4  install $(ALL_DEPS) --lib
+	cabal-ghc-8.2  install $(ALL_DEPS) --lib
+	cabal-ghc-8.0  install $(ALL_DEPS) --lib
+	cabal-ghc-7.10 v1-install $(ALL_DEPS)
+	cabal-ghc-7.8  v1-install $(ALL_DEPS)
+	# (v2-) library installation is supported on GHC 8.0+ only)
 
 hlint:
 	hlint \
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -29,6 +29,11 @@
 	$ cabal update
 	$ cabal install express
 
+Starting from Cabal v3.0, you need to pass `--lib` as an argument to cabal
+install:
+
+	$ cabal install leancheck --lib
+
 
 Basics
 ------
diff --git a/bench/compare.hs b/bench/compare.hs
--- a/bench/compare.hs
+++ b/bench/compare.hs
@@ -1,6 +1,6 @@
 -- ord.hs -- prints results of the Ord Expr's instance
 --
--- Copyright (c) 2019 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 import System.Environment (getArgs)
diff --git a/bench/pairs.hs b/bench/pairs.hs
--- a/bench/pairs.hs
+++ b/bench/pairs.hs
@@ -1,6 +1,6 @@
 -- pairs.hs -- a thousand pairs of expressions
 --
--- Copyright (c) 2019 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 import System.Environment (getArgs)
diff --git a/bench/tiers.hs b/bench/tiers.hs
--- a/bench/tiers.hs
+++ b/bench/tiers.hs
@@ -1,6 +1,6 @@
 -- tiers.hs -- prints tiers of expressions
 --
--- Copyright (c) 2019 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 import Data.List (intercalate, nub)
diff --git a/eg/u-extrapolate.hs b/eg/u-extrapolate.hs
--- a/eg/u-extrapolate.hs
+++ b/eg/u-extrapolate.hs
@@ -1,6 +1,6 @@
 -- u-extrapolate.hs -- micro Extrapolate / Extrapolite
 --
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 --
 -- A small property-based testing library capable of generalizing
diff --git a/eg/u-speculate.hs b/eg/u-speculate.hs
--- a/eg/u-speculate.hs
+++ b/eg/u-speculate.hs
@@ -1,6 +1,6 @@
--- u-extrapolate.hs -- micro Speculate / Speculite
+-- u-speculate.hs -- micro Speculate / Speculite
 --
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 --
 -- A small library capable of conjecturing laws about Haskell functions
@@ -16,7 +16,7 @@
 -- * even with pruning, this program still prints some redundant rules;
 -- * there is no way to configure maximum number of tests to consider an
 --   equation true;
--- * runtime is exponential as you add more symbols to Speculate about.
+-- * runtime is exponential as you add more symbols to speculate about.
 --
 -- Please see Speculate for a full featured version:
 --
diff --git a/express.cabal b/express.cabal
--- a/express.cabal
+++ b/express.cabal
@@ -1,6 +1,6 @@
 -- Cabal file for express
 name: express
-version: 0.1.3
+version: 0.1.4
 synopsis: Dynamically-typed expressions involving applications and variables.
 description:
   Express is a library for manipulating dynamically typed Haskell expressions.
@@ -58,7 +58,7 @@
 source-repository this
   type:           git
   location:       https://github.com/rudymatela/express
-  tag:            v0.1.3
+  tag:            v0.1.4
 
 library
   exposed-modules:     Data.Express
diff --git a/mk/depend.mk b/mk/depend.mk
--- a/mk/depend.mk
+++ b/mk/depend.mk
@@ -174,8 +174,6 @@
   src/Data/Express/Fold.hs \
   src/Data/Express/Core.hs \
   src/Data/Express/Basic.hs
-src/Data/Express/Canon: \
-  mk/toplibs
 src/Data/Express/Canon.o: \
   src/Data/Express/Utils/Typeable.hs \
   src/Data/Express/Utils/String.hs \
@@ -235,6 +233,8 @@
   src/Data/Express/Utils/List.hs \
   src/Data/Express/Fold.hs \
   src/Data/Express/Core.hs
+src/Data/Express/Hole: \
+  mk/toplibs
 src/Data/Express/Hole.o: \
   src/Data/Express/Utils/Typeable.hs \
   src/Data/Express/Utils/String.hs \
diff --git a/mk/ghcdeps b/mk/ghcdeps
--- a/mk/ghcdeps
+++ b/mk/ghcdeps
@@ -2,7 +2,7 @@
 #
 # ghcdeps: generate Haskell make dependencies for compiling with GHC.
 #
-# Copyright (c) 2015-2020 Rudy Matela.
+# Copyright (c) 2015-2021 Rudy Matela.
 # Distributed under the 3-Clause BSD licence.
 #
 # From a list of files provided on standard input,
@@ -46,4 +46,5 @@
 	rm -f tmp.mk
 done |
 sort |
+grep -v "^Loaded package environment from " |
 sed -e 's,  *, \\\n  ,g'
diff --git a/mk/haddock-i b/mk/haddock-i
--- a/mk/haddock-i
+++ b/mk/haddock-i
@@ -2,7 +2,7 @@
 #
 # haddock-i: list haddock's -i parameters.
 #
-# Copyright (c) 2015-2020 Rudy Matela.
+# Copyright (c) 2015-2021 Rudy Matela.
 # Distributed under the 3-Clause BSD licence.
 #
 # $ haddock-i <package1> <package2> ... <packageN>
diff --git a/mk/haskell.mk b/mk/haskell.mk
--- a/mk/haskell.mk
+++ b/mk/haskell.mk
@@ -1,6 +1,6 @@
 # Implicit rules for compiling Haskell code.
 #
-# Copyright (c) 2015-2020 Rudy Matela.
+# Copyright (c) 2015-2021 Rudy Matela.
 # Distributed under the 3-Clause BSD licence.
 #
 # You can optionally configure the "Configuration variables" below in your main
diff --git a/mk/install-on b/mk/install-on
--- a/mk/install-on
+++ b/mk/install-on
@@ -2,9 +2,12 @@
 #
 # mk/install-on: install or updates the mk folder on a Haskell project
 #
+# Copyright (c) 2019-2021 Rudy Matela.
+# Distributed under the 3-Clause BSD licence.
+#
 # usage: ./mk/install-on path/to/project
 #
-# This assumes a few things:
+# This script assumes that:
 #
 # * tests are stored in a "test/" folder
 # * sources are stored in a "src/" folder
diff --git a/src/Data/Express.hs b/src/Data/Express.hs
--- a/src/Data/Express.hs
+++ b/src/Data/Express.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
@@ -140,6 +140,7 @@
   , isConst
   , isIllTyped
   , isWellTyped
+  , isFun
   , hasVar
   , isGround
 
@@ -196,7 +197,7 @@
   , holes
   , nubHoles
   , holeAsTypeOf
-
+  , fill
 
   -- -- -- Data.Express.Fold exports -- -- --
 
@@ -222,7 +223,11 @@
   , isCanonical
   , isCanonicalWith
   , canonicalVariations
+  , mostGeneralCanonicalVariation
+  , mostSpecificCanonicalVariation
   , fastCanonicalVariations
+  , fastMostGeneralVariation
+  , fastMostSpecificVariation
 
   -- -- -- Data.Express.Match exports -- -- --
 
diff --git a/src/Data/Express/Basic.hs b/src/Data/Express/Basic.hs
--- a/src/Data/Express/Basic.hs
+++ b/src/Data/Express/Basic.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Basic
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Canon.hs b/src/Data/Express/Canon.hs
--- a/src/Data/Express/Canon.hs
+++ b/src/Data/Express/Canon.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Canon
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
@@ -13,7 +13,11 @@
   , isCanonical
   , isCanonicalWith
   , canonicalVariations
+  , mostGeneralCanonicalVariation
+  , mostSpecificCanonicalVariation
   , fastCanonicalVariations
+  , fastMostGeneralVariation
+  , fastMostSpecificVariation
   )
 where
 
@@ -175,6 +179,84 @@
 canonicalVariations = map canonicalize . fastCanonicalVariations
 
 -- |
+-- Returns the most general canonical variation of an 'Expr'
+-- by filling holes with variables.
+--
+-- > > mostGeneralCanonicalVariation $ i_
+-- > x :: Int
+--
+-- > > mostGeneralCanonicalVariation $ i_ -+- i_
+-- > x + y :: Int
+--
+-- > > mostGeneralCanonicalVariation $ i_ -+- i_ -+- i_
+-- > (x + y) + z :: Int
+--
+-- > > mostGeneralCanonicalVariation $ i_ -+- ord' c_
+-- > x + ord c :: Int
+--
+-- > > mostGeneralCanonicalVariation $ i_ -+- i_ -+- ord' c_
+-- > (x + y) + ord c :: Int
+--
+-- > > mostGeneralCanonicalVariation $ i_ -+- i_ -+- length' (c_ -:- unit c_)
+-- > (x + y) + length (c:d:"") :: Int
+--
+-- In an expression without holes this functions just returns
+-- the given expression itself:
+--
+-- > > mostGeneralCanonicalVariation $ val (0 :: Int)
+-- > 0 :: Int
+--
+-- > > mostGeneralCanonicalVariation $ ord' bee
+-- > ord 'b' :: Int
+--
+-- Behaviour is undefined when applying this function to expressions already
+-- containing variables.
+--
+-- This function is the same as taking the 'head' of 'canonicalVariations'
+-- but a bit faster.
+mostGeneralCanonicalVariation :: Expr -> Expr
+mostGeneralCanonicalVariation  =  canonicalize . fastMostGeneralVariation
+
+-- |
+-- Returns the most specific canonical variation of an 'Expr'
+-- by filling holes with variables.
+--
+-- > > mostSpecificCanonicalVariation $ i_
+-- > x :: Int
+--
+-- > > mostSpecificCanonicalVariation $ i_ -+- i_
+-- > x + x :: Int
+--
+-- > > mostSpecificCanonicalVariation $ i_ -+- i_ -+- i_
+-- > (x + x) + x :: Int
+--
+-- > > mostSpecificCanonicalVariation $ i_ -+- ord' c_
+-- > x + ord c :: Int
+--
+-- > > mostSpecificCanonicalVariation $ i_ -+- i_ -+- ord' c_
+-- > (x + x) + ord c :: Int
+--
+-- > > mostSpecificCanonicalVariation $ i_ -+- i_ -+- length' (c_ -:- unit c_)
+-- > (x + x) + length (c:c:"") :: Int
+--
+-- In an expression without holes this functions just returns
+-- the given expression itself:
+--
+-- > > mostSpecificCanonicalVariation $ val (0 :: Int)
+-- > 0 :: Int
+--
+-- > > mostSpecificCanonicalVariation $ ord' bee
+-- > ord 'b' :: Int
+--
+-- Behaviour is undefined when applying this function to expressions already
+-- containing variables.
+--
+-- This function is the same as taking the 'last' of 'canonicalVariations'
+-- but a bit faster.
+mostSpecificCanonicalVariation :: Expr -> Expr
+mostSpecificCanonicalVariation  =  canonicalize . fastMostSpecificVariation
+
+-- |
 -- A faster version of 'canonicalVariations' that
 -- disregards name clashes across different types.
 -- Results are confusing to the user
@@ -216,19 +298,20 @@
            : [ map (n `varAsTypeOf` h:) (fillings i hs) -- no new variable
              | n <- take i names ]
 
+-- |
+-- A faster version of 'mostGeneralCanonicalVariation'
+-- that disregards name clashes across different types.
+-- Consider using 'mostGeneralCanonicalVariation' instead.
+--
+-- The same caveats of 'fastCanonicalVariations' do apply here.
+fastMostGeneralVariation :: Expr -> Expr
+fastMostGeneralVariation e  =  fill e (zipWith varAsTypeOf (variableNamesFromTemplate "x") (holes e))
 
--- | Fill holes in an expression.
---   Silently skips holes that are not of the right type.
---   Silently discard remaining expressions.
-fill :: Expr -> [Expr] -> Expr
-fill e = fst . fill' e
-  where
-  fill' :: Expr -> [Expr] -> (Expr,[Expr])
-  fill' (e1 :$ e2) es = let (e1',es')  = fill' e1 es
-                            (e2',es'') = fill' e2 es'
-                        in (e1' :$ e2', es'')
-  fill' eh (e:es) | isHole eh && typ eh == typ e = (e,es)
-  fill' e es = (e,es)
--- TODO: copy tests from Speculate
--- TODO: add examples on Haddock
--- TODO: export? consider exporting 'fill' from the Hole module
+-- |
+-- A faster version of 'mostSpecificCanonicalVariation'
+-- that disregards name clashes across different types.
+-- Consider using 'mostSpecificCanonicalVariation' instead.
+--
+-- The same caveats of 'fastCanonicalVariations' do apply here.
+fastMostSpecificVariation :: Expr -> Expr
+fastMostSpecificVariation e  =  fill e (map ("x" `varAsTypeOf`) (holes e))
diff --git a/src/Data/Express/Core.hs b/src/Data/Express/Core.hs
--- a/src/Data/Express/Core.hs
+++ b/src/Data/Express/Core.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Core
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
@@ -42,6 +42,7 @@
   , isConst
   , isIllTyped
   , isWellTyped
+  , isFun
   , hasVar
   , isGround
 
@@ -324,6 +325,21 @@
 isWellTyped :: Expr -> Bool
 isWellTyped  =  isJust . mtyp
 
+-- | /O(n)/.
+-- Returns whether the given 'Expr' is of a functional type.
+-- This is the same as checking if the 'arity' of the given 'Expr' is non-zero.
+--
+-- > > isFun (value "abs" (abs :: Int -> Int))
+-- > True
+--
+-- > > isFun (val (1::Int))
+-- > False
+--
+-- > > isFun (value "const" (const :: Bool -> Bool -> Bool) :$ val False)
+-- > True
+isFun :: Expr -> Bool
+isFun  =  isFunTy . typ
+
 -- |  /O(n)/.
 -- 'Just' the value of an expression when possible (correct type),
 -- 'Nothing' otherwise.
@@ -430,24 +446,26 @@
 showsPrecExpr d (Value s _) | isNegativeLiteral s = showParen (d > 0) $ showString s
 showsPrecExpr d (Value s _) = showParen sp $ showString s
   where sp = if atomic s then isInfix s else maybe True (d >) $ outernmostPrec s
-showsPrecExpr d ((Value ":" _ :$ e1) :$ e2)
+showsPrecExpr d (Value ":" _ :$ e1 :$ e2)
   | isConst e1 && mtyp e1 == Just (typeOf (undefined :: Char)) =
   case showsTailExpr e2 "" of
     '\"':cs  -> showString ("\"" ++ (init . tail) (showsPrecExpr 0 e1 "") ++ cs)
     cs -> showParen (d > prec ":")
         $ showsOpExpr ":" e1 . showString ":" . showString cs
-showsPrecExpr d ((Value ":" _ :$ e1) :$ e2) =
+showsPrecExpr d (Value ":" _ :$ e1 :$ e2) =
   case showsTailExpr e2 "" of
     "[]" -> showString "[" . showsPrecExpr 0 e1 . showString "]"
     '[':cs -> showString "[" . showsPrecExpr 0 e1 . showString "," . showString cs
     cs -> showParen (d > prec ":")
         $ showsOpExpr ":" e1 . showString ":" . showString cs
-showsPrecExpr d ee | isTuple ee = id
-    showString "("
-  . foldr1 (\s1 s2 -> s1 . showString "," . s2)
-           (showsPrecExpr 0 `map` unfoldTuple ee)
-  . showString ")"
-showsPrecExpr d ((Value f' _ :$ e1) :$ e2)
+showsPrecExpr d ee | isTuple ee = showParen True
+                                $ foldr1 (\s1 s2 -> s1 . showString "," . s2)
+                                         (showsPrecExpr 0 `map` unfoldTuple ee)
+showsPrecExpr d (Value "if" _ :$ ep :$ ex :$ ey) =
+  showParen (d >= 0) $ showString "if "    . showsPrecExpr 0 ep
+                     . showString " then " . showsPrecExpr 0 ex
+                     . showString " else " . showsPrecExpr 0 ey
+showsPrecExpr d (Value f' _ :$ e1 :$ e2)
   | isInfix f = showParen (d > prec f)
               $ showsOpExpr f e1
               . showString " " . showString f . showString " "
@@ -461,8 +479,7 @@
                  ('_':f) -> f -- on variables we drop the preceding _
                  f -> f       -- constants as themselves
 showsPrecExpr d (Value f' _ :$ e1)
-  | isInfix f = showParen True
-              $ showsOpExpr f e1 . showString " " . showString f
+  | isInfix f = showParen True $ showsOpExpr f e1 . showString " " . showString f
   where
   f = case f' of "_" -> "_"   -- holes are shown as _
                  ('_':f) -> f -- on variables we drop the preceding _
@@ -474,12 +491,12 @@
 
 -- bad smell here, repeated code!
 showsTailExpr :: Expr -> String -> String
-showsTailExpr ((Value ":" _ :$ e1) :$ e2)
+showsTailExpr (Value ":" _ :$ e1 :$ e2)
   | isConst e1 && mtyp e1 == Just (typeOf (undefined :: Char)) =
   case showsPrecExpr 0 e2 "" of
     '\"':cs  -> showString ("\"" ++ (init . tail) (showsPrecExpr 0 e1 "") ++ cs)
     cs -> showsOpExpr ":" e1 . showString ":" . showsTailExpr e2
-showsTailExpr ((Value ":" _ :$ e1) :$ e2) =
+showsTailExpr (Value ":" _ :$ e1 :$ e2) =
   case showsPrecExpr 0 e2 "" of
     "[]" -> showString "[" . showsPrecExpr 0 e1 . showString "]"
     '[':cs -> showString "[" . showsPrecExpr 0 e1 . showString "," . showString cs
@@ -506,7 +523,7 @@
 -- > > putStrLn $ showExpr $ (pp -||- true) -&&- (qq -||- false)
 -- > (p || True) && (q || False)
 showExpr :: Expr -> String
-showExpr = showPrecExpr 0
+showExpr = showPrecExpr (-1)
 
 -- | /O(n)/.
 --   Does not evaluate values when comparing, but rather uses their
@@ -786,7 +803,7 @@
   s e@(e1 :$ e2)  =  (e:) . s e1 . s e2
   s e             =  (e:)
 
--- | /O(n log n)/ for the spine, /O(n^2)/ for full evaluation.
+-- | Average /O(n log n)/ for the spine, /O(n^2)/ for full evaluation.
 -- Lists all subexpressions of a given expression without repetitions.
 -- This includes the expression itself and partial function applications.
 -- (cf. 'subexprs')
@@ -807,16 +824,14 @@
 -- > , p && True :: Bool
 -- > , p && (p && True) :: Bool
 -- > ]
+--
+-- While this is /O(n log n)/ on average it is /O(n^2)/ in the worst-case
+-- (f (g (h (i (j (k (l (m (n x))))))))).
 nubSubexprs :: Expr -> [Expr]
 nubSubexprs  =  s
   where
   s e@(e1 :$ e2)  =  [e] +++ s e1 +++ s e2
   s e             =  [e]
--- TODO: After deciding if I'll stick to this implementation or the old one,
--- add note about complexity:
---
--- While this is /O(n log n)/ on average it is /O(n^2)/ in the worst-case.
--- Worst case = f (g (h (i (j (k (l (m (n x))))))))
 
 -- | /O(n)/.
 -- Lists all terminal values in an expression in order and with repetitions.
diff --git a/src/Data/Express/Express.hs b/src/Data/Express/Express.hs
--- a/src/Data/Express/Express.hs
+++ b/src/Data/Express/Express.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Express
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Express/Derive.hs b/src/Data/Express/Express/Derive.hs
--- a/src/Data/Express/Express/Derive.hs
+++ b/src/Data/Express/Express/Derive.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE TemplateHaskell, CPP #-}
 -- |
 -- Module      : Data.Express.Express.Derive
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Fixtures.hs b/src/Data/Express/Fixtures.hs
--- a/src/Data/Express/Fixtures.hs
+++ b/src/Data/Express/Fixtures.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Fixtures
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
@@ -110,6 +110,7 @@
   , (-<=-)
   , (-<-)
   , compare'
+  , if'
 
   -- ** Integers
   , i_, xx, yy, zz, xx'
@@ -158,6 +159,7 @@
   , (-++-)
   , head'
   , tail'
+  , null'
   , length'
   , elem'
   , sort'
@@ -273,6 +275,7 @@
 
 (-==>-) :: Expr -> Expr -> Expr
 e1 -==>- e2  =  implies :$ e1 :$ e2
+infixr 0 -==>-
 
 implies :: Expr
 implies  =  value "==>" (==>)
@@ -305,6 +308,7 @@
 -- > False
 (-&&-) :: Expr -> Expr -> Expr
 pp -&&- qq  =  andE :$ pp :$ qq
+infixr 3 -&&-
 
 -- | The function '||' lifted over the 'Expr' type.
 --
@@ -318,6 +322,7 @@
 -- > True
 (-||-) :: Expr -> Expr -> Expr
 pp -||- qq  =  orE :$ pp :$ qq
+infixr 2 -||-
 
 -- | A typed hole of 'Int' type.
 --
@@ -504,6 +509,7 @@
 -- > 2 * x :: Int
 (-*-) :: Expr -> Expr -> Expr
 e1 -*- e2 = times :$ e1 :$ e2
+infixl 7 -*-
 
 -- | The operator '*' for the 'Int' type.  (See also '-*-'.)
 --
@@ -851,6 +857,26 @@
   where
   err  =  error $ "tail': unhandled type " ++ show (typ exs)
 
+-- | List 'null' lifted over the 'Expr' type.
+--   Works for the element types 'Int', 'Char' and 'Bool'.
+--
+-- > > null' $ unit one
+-- > null [1] :: Bool
+--
+-- > > null' $ nil
+-- > null [] :: Bool
+--
+-- > > evl $ null' nil :: Bool
+-- > True
+null' :: Expr -> Expr
+null' exs = headOr err $ mapMaybe ($$ exs)
+  [ value "null" (null :: [Int] -> Bool)
+  , value "null" (null :: [Char] -> Bool)
+  , value "null" (null :: [Bool] -> Bool)
+  ]
+  where
+  err  =  error $ "null': unhandled type " ++ show (typ exs)
+
 -- | List 'length' lifted over the 'Expr' type.
 --   Works for the element types 'Int', 'Char' and 'Bool'.
 --
@@ -971,6 +997,36 @@
   where
   err  =  error $ "(-<-): unhandled type " ++ show (typ ex)
 infix 4 -<-
+
+-- | A virtual function @if :: Bool -> a -> a -> a@ lifted over the 'Expr' type.
+--   This is displayed as an if-then-else.
+--
+-- > > if' pp zero xx
+-- > (if p then 0 else x) :: Int
+--
+-- > > zz -*- if' pp xx yy
+-- > z * (if p then x else y) :: Int
+--
+-- > > if' pp false true -||- if' qq true false
+-- > (if p then False else True) || (if q then True else False) :: Bool
+--
+-- > > evl $ if' true (val 't') (val 'f') :: Char
+-- > 't'
+if' :: Expr -> Expr -> Expr -> Expr
+if' ep ex ey  =  (:$ ey) . headOr err . mapMaybe ($$ ex) $ map (:$ ep)
+  [ value "if" (iff :: If ())
+  , value "if" (iff :: If Int)
+  , value "if" (iff :: If Bool)
+  , value "if" (iff :: If Char)
+  , value "if" (iff :: If [Int])
+  , value "if" (iff :: If [Bool])
+  , value "if" (iff :: If [Char])
+  ]
+  where
+  err  =  error $ "if': unhandled type " ++ show (typ ex)
+  iff :: Bool -> a -> a -> a
+  iff p x y  =  if p then x else y
+type If a = Bool -> a -> a -> a
 
 compare' :: Expr -> Expr -> Expr
 compare' ex ey  =  (:$ ey) . headOr err $ mapMaybe ($$ ex)
diff --git a/src/Data/Express/Fold.hs b/src/Data/Express/Fold.hs
--- a/src/Data/Express/Fold.hs
+++ b/src/Data/Express/Fold.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Fold
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
@@ -128,6 +128,6 @@
 -- > > unfold $ expr [1,2,3::Int]
 -- > [1 :: Int,2 :: Int,3 :: Int]
 unfold :: Expr -> [Expr]
-unfold   (Value "[]" _)               =  []
-unfold (((Value ":"  _) :$ e) :$ es)  =  e : unfold es
+unfold (Value "[]" _)             =  []
+unfold (Value ":"  _ :$ e :$ es)  =  e : unfold es
 unfold e  =  error $ "unfold: cannot unfold expression: " ++ show e
diff --git a/src/Data/Express/Hole.hs b/src/Data/Express/Hole.hs
--- a/src/Data/Express/Hole.hs
+++ b/src/Data/Express/Hole.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Hole
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
@@ -19,6 +19,7 @@
   , holes
   , nubHoles
   , holeAsTypeOf
+  , fill
   )
 where
 
@@ -178,3 +179,47 @@
 -- > ]
 listVarsAsTypeOf :: String -> Expr -> [Expr]
 listVarsAsTypeOf s e  =  map (`varAsTypeOf` e) (variableNamesFromTemplate s)
+
+
+-- | Fill holes in an expression with the given list.
+--
+-- > > let i_  =  hole (undefined :: Int)
+-- > > let e1 -+- e2  =  value "+" ((+) :: Int -> Int -> Int) :$ e1 :$ e2
+-- > > let xx  =  var "x" (undefined :: Int)
+-- > > let yy  =  var "y" (undefined :: Int)
+--
+-- > > fill (i_ -+- i_) [xx, yy]
+-- > x + y :: Int
+--
+-- > > fill (i_ -+- i_) [xx, xx]
+-- > x + x :: Int
+--
+-- > > let one  =  val (1::Int)
+--
+-- > > fill (i_ -+- i_) [one, one -+- one]
+-- > 1 + (1 + 1) :: Int
+--
+-- This function silently remaining expressions:
+--
+-- > > fill i_ [xx, yy]
+-- > x :: Int
+--
+-- This function silently keeps remaining holes:
+--
+-- > > fill (i_ -+- i_ -+- i_) [xx, yy]
+-- > (x + y) + _ :: Int
+--
+-- This function silently skips remaining holes
+-- if one is not of the right type:
+--
+-- > > fill (i_ -+- i_ -+- i_) [xx, val 'c', yy]
+-- > (x + _) + _ :: Int
+fill :: Expr -> [Expr] -> Expr
+fill e = fst . fill' e
+  where
+  fill' :: Expr -> [Expr] -> (Expr,[Expr])
+  fill' (e1 :$ e2) es = let (e1',es')  = fill' e1 es
+                            (e2',es'') = fill' e2 es'
+                        in (e1' :$ e2', es'')
+  fill' eh (e:es) | isHole eh && typ eh == typ e = (e,es)
+  fill' e es = (e,es)
diff --git a/src/Data/Express/Instances.hs b/src/Data/Express/Instances.hs
--- a/src/Data/Express/Instances.hs
+++ b/src/Data/Express/Instances.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Instances
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Map.hs b/src/Data/Express/Map.hs
--- a/src/Data/Express/Map.hs
+++ b/src/Data/Express/Map.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Map
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Match.hs b/src/Data/Express/Match.hs
--- a/src/Data/Express/Match.hs
+++ b/src/Data/Express/Match.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Match
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Name.hs b/src/Data/Express/Name.hs
--- a/src/Data/Express/Name.hs
+++ b/src/Data/Express/Name.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Name
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Name/Derive.hs b/src/Data/Express/Name/Derive.hs
--- a/src/Data/Express/Name/Derive.hs
+++ b/src/Data/Express/Name/Derive.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE TemplateHaskell, CPP #-}
 -- |
 -- Module      : Data.Express.Name.Derive
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Utils/List.hs b/src/Data/Express/Utils/List.hs
--- a/src/Data/Express/Utils/List.hs
+++ b/src/Data/Express/Utils/List.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Utils.List
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Utils/String.hs b/src/Data/Express/Utils/String.hs
--- a/src/Data/Express/Utils/String.hs
+++ b/src/Data/Express/Utils/String.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Utils.String
--- Copyright   : (c) 2016-2020 Rudy Matela
+-- Copyright   : (c) 2016-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
@@ -91,38 +91,38 @@
 
 -- | Returns the precedence of default Haskell operators
 prec :: String -> Int
-prec " "  = 10
-prec "!!" = 9
-prec "."  = 9
-prec "^"  = 8
-prec "^^" = 8
-prec "**" = 8
-prec "*"  = 7
-prec "/"  = 7
-prec "%"  = 7
-prec "+"  = 6
-prec "-"  = 6
-prec ":"  = 5
-prec "++" = 5
-prec "\\" = 5
-prec ">"  = 4
-prec "<"  = 4
-prec ">=" = 4
-prec "<=" = 4
-prec "==" = 4
-prec "/=" = 4
-prec "`elem`" = 4
-prec "&&" = 3
-prec "||" = 2
-prec ">>=" = 1
-prec ">>" = 1
-prec ">=>" = 1
-prec "<=<" = 1
-prec "$"  = 0
-prec "`seq`" = 0
-prec "==>" = 0
-prec "<==>" = 0
-prec _ = 9
+prec " "       =  10
+prec "!!"      =   9
+prec "."       =   9
+prec "^"       =   8
+prec "^^"      =   8
+prec "**"      =   8
+prec "*"       =   7
+prec "/"       =   7
+prec "%"       =   7
+prec "+"       =   6
+prec "-"       =   6
+prec ":"       =   5
+prec "++"      =   5
+prec "\\"      =   5
+prec ">"       =   4
+prec "<"       =   4
+prec ">="      =   4
+prec "<="      =   4
+prec "=="      =   4
+prec "/="      =   4
+prec "`elem`"  =   4
+prec "&&"      =   3
+prec "||"      =   2
+prec ">>="     =   1
+prec ">>"      =   1
+prec ">=>"     =   1
+prec "<=<"     =   1
+prec "$"       =   0
+prec "`seq`"   =   0
+prec "==>"     =   0
+prec "<==>"    =   0
+prec _         =   9
 
 isPrefix :: String -> Bool
 isPrefix = not . isInfix
diff --git a/src/Data/Express/Utils/TH.hs b/src/Data/Express/Utils/TH.hs
--- a/src/Data/Express/Utils/TH.hs
+++ b/src/Data/Express/Utils/TH.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE TemplateHaskell, CPP #-}
 -- |
 -- Module      : Data.Express.Name.Derive
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/src/Data/Express/Utils/Typeable.hs b/src/Data/Express/Utils/Typeable.hs
--- a/src/Data/Express/Utils/Typeable.hs
+++ b/src/Data/Express/Utils/Typeable.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Express.Utils.Typeable
--- Copyright   : (c) 2016-2020 Rudy Matela
+-- Copyright   : (c) 2016-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Test
--- Copyright   : (c) 2019-2020 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/test/Test/ListableExpr.hs b/test/Test/ListableExpr.hs
--- a/test/Test/ListableExpr.hs
+++ b/test/Test/ListableExpr.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Test.ListableExpr
--- Copyright   : (c) 2019 Rudy Matela
+-- Copyright   : (c) 2019-2021 Rudy Matela
 -- License     : 3-Clause BSD  (see the file LICENSE)
 -- Maintainer  : Rudy Matela <rudy@matela.com.br>
 --
diff --git a/test/canon.hs b/test/canon.hs
--- a/test/canon.hs
+++ b/test/canon.hs
@@ -1,12 +1,12 @@
--- Copyright (c) 2017-2020 Rudy Matela.
+-- Copyright (c) 2017-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
 main :: IO ()
-main = mainTest tests 5040
+main  =  mainTest tests 5040
 
 tests :: Int -> [Bool]
-tests n =
+tests n  =
   [ True
 
   , canonicalize (xx -+- yy)
@@ -102,19 +102,22 @@
                     in length (nub (sort es)) == length es
   , holds n $ \e -> length (canonicalVariations e)
                  == product (map (bell . snd) . counts $ holes e)
+
+  , holds n $ \e -> all isHole (vars e) ==> head (canonicalVariations e) == mostGeneralCanonicalVariation e
+  , holds n $ \e -> all isHole (vars e) ==> last (canonicalVariations e) == mostSpecificCanonicalVariation e
   ]
 
 -- O(1) bell number implementation
 -- only works up to 8
 -- but this is enough for testing.
 bell :: Int -> Int
-bell 0 = 1
-bell 1 = 1
-bell 2 = 2
-bell 3 = 5
-bell 4 = 15
-bell 5 = 52
-bell 6 = 203
-bell 7 = 877
-bell 8 = 4140
-bell _ = error "bell: argument > 8, implement me!"
+bell 0  =  1
+bell 1  =  1
+bell 2  =  2
+bell 3  =  5
+bell 4  =  15
+bell 5  =  52
+bell 6  =  203
+bell 7  =  877
+bell 8  =  4140
+bell _  =  error "bell: argument > 8, implement me!"
diff --git a/test/core.hs b/test/core.hs
--- a/test/core.hs
+++ b/test/core.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
@@ -72,6 +72,11 @@
   , isIllTyped (zero :$ one) == True
   , isWellTyped (abs' zero) == True
   , isWellTyped (zero :$ one) == False
+
+  , isFun (value "abs" (abs :: Int -> Int)) == True
+  , isFun (val (1::Int)) == False
+  , isFun (value "const" (const :: Bool -> Bool -> Bool) :$ val False) == True
+  , holds n $ \e -> (arity e /= 0) == isFun e
 
   -- eq instance
   , xx -+- yy == xx -+- yy
diff --git a/test/express-derive.hs b/test/express-derive.hs
--- a/test/express-derive.hs
+++ b/test/express-derive.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE DeriveDataTypeable #-}
diff --git a/test/express.hs b/test/express.hs
--- a/test/express.hs
+++ b/test/express.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 {-# LANGUAGE CPP #-}
 import Test
diff --git a/test/fixtures.hs b/test/fixtures.hs
--- a/test/fixtures.hs
+++ b/test/fixtures.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2017-2020 Rudy Matela.
+-- Copyright (c) 2017-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
@@ -170,4 +170,8 @@
   , evl (unit bee) == "b"
   , evl (bee -:- unit cee) == "bc"
   , evl (bee -:- cee -:- unit dee) == "bcd"
+
+  -- if --
+  , evl (if' false zero one) == (1 :: Int)
+  , evl (if' true two three) == (2 :: Int)
   ]
diff --git a/test/fold.hs b/test/fold.hs
--- a/test/fold.hs
+++ b/test/fold.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
diff --git a/test/hole.hs b/test/hole.hs
--- a/test/hole.hs
+++ b/test/hole.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
@@ -27,4 +27,18 @@
   , [pp, qq, rr, pp'] `isPrefixOf` listVars "p" (undefined :: Bool)
   , [xx, yy, zz, xx'] `isPrefixOf` listVarsAsTypeOf "x" zero
   , [pp, qq, rr, pp'] `isPrefixOf` listVarsAsTypeOf "p" false
+
+  -- fill unit tests
+  , fill (i_ -+- i_) [xx, yy] == xx -+- yy
+  , fill (i_ -+- i_) [xx, xx] == xx -+- xx
+  , fill (i_ -+- i_) [one, one -+- one] == one -+- (one -+- one)
+
+  -- silent behaviours of fill
+  , fill (i_ -+- i_ -+- i_) [xx, yy] == xx -+- yy -+- i_
+  , fill (i_) [xx, yy] == xx
+  , fill (i_ -+- i_ -+- i_) [xx, val 'c', yy] == xx -+- i_ -+- i_
+
+  -- fill properties
+  , holds n $ \(IntE e) -> fill (zero -+- i_ -+- two) [e] == zero -+- e -+- two
+  , holds n $ \(IntE e1, IntE e2) -> fill (i_ -+- one -+- i_) [e1, e2] == e1 -+- one -+- e2
   ]
diff --git a/test/instances.hs b/test/instances.hs
--- a/test/instances.hs
+++ b/test/instances.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2017-2020 Rudy Matela.
+-- Copyright (c) 2017-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 {-# LANGUAGE NoMonomorphismRestriction #-} -- ACK!
 import Test
diff --git a/test/listable.hs b/test/listable.hs
--- a/test/listable.hs
+++ b/test/listable.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2017-2020 Rudy Matela.
+-- Copyright (c) 2017-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
diff --git a/test/map.hs b/test/map.hs
--- a/test/map.hs
+++ b/test/map.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 import Test.LeanCheck.Function
diff --git a/test/match.hs b/test/match.hs
--- a/test/match.hs
+++ b/test/match.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
diff --git a/test/name-derive.hs b/test/name-derive.hs
--- a/test/name-derive.hs
+++ b/test/name-derive.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 {-# LANGUAGE TemplateHaskell #-}
 
diff --git a/test/name.hs b/test/name.hs
--- a/test/name.hs
+++ b/test/name.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2017-2020 Rudy Matela.
+-- Copyright (c) 2017-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
diff --git a/test/ord.hs b/test/ord.hs
--- a/test/ord.hs
+++ b/test/ord.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2019-2020 Rudy Matela.
+-- Copyright (c) 2019-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
diff --git a/test/sdist b/test/sdist
--- a/test/sdist
+++ b/test/sdist
@@ -2,7 +2,7 @@
 #
 # test/sdist: tests the package generated by "cabal sdist".
 #
-# Copyright (c) 2015-2020 Rudy Matela.
+# Copyright (c) 2015-2021 Rudy Matela.
 # Distributed under the 3-Clause BSD licence.
 
 set -xe
diff --git a/test/show.hs b/test/show.hs
--- a/test/show.hs
+++ b/test/show.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2017-2020 Rudy Matela.
+-- Copyright (c) 2017-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
@@ -37,7 +37,6 @@
   , show (value "`compare`" (compare :: Int->Int->Ordering) :$ one :$ two) == "1 `compare` 2 :: Ordering"
 
   , holds n $ show . mapVars (\(Value ('_':s) d) -> Value (if null s then "_" else s) d) === show
---, holds n $ show . mapConsts (\(Value s d) -> Value ('_':s) d) === show -- TODO:
 
   , show emptyString == "\"\" :: [Char]"
   , show (space -:- emptyString) == "\" \" :: [Char]"
@@ -74,6 +73,23 @@
   , show (ffE -$- minusOne) == "f $ (-1) :: Int"
 
   , holds n $ \e -> showExpr e `isPrefixOf` show e
+
+  , show (if' pp xx yy)             == "(if p then x else y) :: Int"
+  , show (if' false zero one)       == "(if False then 0 else 1) :: Int"
+  , show (if' true two three)       == "(if True then 2 else 3) :: Int"
+  , show (if' pp false true)        == "(if p then False else True) :: Bool"
+  , show (not' (if' pp false true)) == "not (if p then False else True) :: Bool"
+  , show (if' pp xx yy -*- zz)      == "(if p then x else y) * z :: Int"
+  , show (zz -*- if' pp xx yy)      == "z * (if p then x else y) :: Int"
+  , show (if' pp false true -||- if' qq true false)
+    == "(if p then False else True) || (if q then True else False) :: Bool"
+  , show (if' (null' xxs) zero (head' xxs -+- value "sum" (sum :: [Int] -> Int) :$ tail' xxs))
+    == "(if null xs then 0 else head xs + sum (tail xs)) :: Int"
+
+  , showExpr (if' pp xx yy)             == "if p then x else y"
+  , showExpr (if' false zero one)       == "if False then 0 else 1"
+  , showExpr (if' true two three)       == "if True then 2 else 3"
+  , showExpr (if' pp false true)        == "if p then False else True"
 
   -- showing holes --
   , show (hole (undefined :: Int -> Int) :$ one)              == "_ 1 :: Int"
diff --git a/test/utils.hs b/test/utils.hs
--- a/test/utils.hs
+++ b/test/utils.hs
@@ -1,4 +1,4 @@
--- Copyright (c) 2017-2020 Rudy Matela.
+-- Copyright (c) 2017-2021 Rudy Matela.
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 import Test
 
