diff --git a/speculate.cabal b/speculate.cabal
--- a/speculate.cabal
+++ b/speculate.cabal
@@ -1,5 +1,5 @@
 name:                speculate
-version:             0.2.10
+version:             0.3.0
 synopsis:            discovery of properties about Haskell functions
 description:
   Speculate automatically discovers laws about Haskell functions.
@@ -31,7 +31,7 @@
 source-repository this
   type:            git
   location:        https://github.com/rudymatela/speculate
-  tag:             v0.2.10
+  tag:             v0.3.0
 
 
 library
diff --git a/src/Test/Speculate/Engine.hs b/src/Test/Speculate/Engine.hs
--- a/src/Test/Speculate/Engine.hs
+++ b/src/Test/Speculate/Engine.hs
@@ -10,6 +10,8 @@
 module Test.Speculate.Engine
   ( vassignments
   , expansions
+  , expansionsOfType
+  , expansionsWith
   , mostGeneral
   , mostSpecific
 
@@ -21,6 +23,7 @@
   , consider
   , distinctFromSchemas
   , classesFromSchemas
+  , classesFromSchemasAndVariables
 
   , semiTheoryFromThyAndReps
 
@@ -79,16 +82,43 @@
 vassignmentsEqn :: (Expr,Expr) -> [(Expr,Expr)]
 vassignmentsEqn = filter (uncurry (/=)) . map unEquation . vassignments . uncurry phonyEquation
 
+-- | List all variable assignments for a given type and list of variables.
+expansionsOfType :: TypeRep -> [String] -> Expr -> [Expr]
+expansionsOfType t vs e = [ fill e [Var v t | v <- vs']
+                          | vs' <- placements (countHoles t e) vs ]
+  where
+  placements :: Int -> [a] -> [[a]]
+  placements 0 xs = [[]]
+  placements n xs = [y:ys | y <- xs, ys <- placements (n-1) xs]
+
+expansionsWith :: [Expr] -> Expr -> [Expr]
+expansionsWith es = ew (collectWith typ nam (,) es)
+  where
+  nam (Var s _) = s
+  typ (Var _ t) = t
+  ew :: [(TypeRep,[String])] -> Expr -> [Expr]
+  ew []            e = [e]
+  ew ((t,ns):tnss) e = ew tnss
+           `concatMap` expansionsOfType t ns e
+
+-- | List all variable assignments for a given number of variables.
+--   It only assign variables to holes (variables with "" as its name).
+--
+-- > > expansions preludeInstances 2 '(_ + _ + ord _)
+-- > [ (x + x) + ord c :: Int
+-- > , (x + x) + ord d :: Int
+-- > , (x + y) + ord c :: Int
+-- > , (x + y) + ord d :: Int
+-- > , (y + x) + ord c :: Int
+-- > , (y + x) + ord d :: Int
+-- > , (y + y) + ord c :: Int
+-- > , (y + y) + ord d :: Int ]
 expansions :: Instances -> Int -> Expr -> [Expr]
 expansions ti n e =
-  [ foldl fill e [ [ Var (names ti t !! i) t | i <- is ]
-                 | (t,is) <- fs ]
-  | fs <- productsList [[(t,is) | is <- foo c n] | (t,c) <- counts (holes e)] ]
-  where
-  foo :: Int -> Int -> [[Int]]
-  foo 0 nVars = [[]]
-  foo nPos nVars = [i:is | i <- [0..(nVars-1)], is <- foo (nPos-1) nVars]
--- TODO: test expansions, put foo together with iss
+  case counts (holes e) of
+    []      -> [e]
+    (t,c):_ -> expansions ti n `concatMap`
+               expansionsOfType t (take n (names ti t)) e
 
 -- | List the most general assignment of holes in an expression
 mostGeneral :: Expr -> Expr
@@ -198,6 +228,16 @@
 classesFromSchema ti thy n = C.mergesOn (normalizeE thy)
                            . map C.fromRep
                            . expansions ti n
+
+classesFromSchemasAndVariables :: Thy -> [Expr] -> [Expr] -> [Class Expr]
+classesFromSchemasAndVariables thy vs = C.mergesOn (normalizeE thy)
+                                      . concatMap (classesFromSchemaAndVariables thy vs)
+
+classesFromSchemaAndVariables :: Thy -> [Expr] -> Expr -> [Class Expr]
+classesFromSchemaAndVariables thy vs = C.mergesOn (normalizeE thy)
+                                     . map C.fromRep
+                                     . filter (null . holes)
+                                     . expansionsWith vs
 
 -- Return relevant equivalences between holed expressions:
 --
diff --git a/src/Test/Speculate/Expr/Core.hs b/src/Test/Speculate/Expr/Core.hs
--- a/src/Test/Speculate/Expr/Core.hs
+++ b/src/Test/Speculate/Expr/Core.hs
@@ -43,6 +43,7 @@
   -- * Properties of expressions
   , lengthE
   , depthE
+  , countHoles
   , countVar
   , countVars
   , unrepeatedVars
@@ -399,6 +400,10 @@
 depthE :: Expr -> Int
 depthE e@(_:$_) = 1 + maximum (map depthE $ unfoldApp e)
 depthE _        = 1
+
+-- | Number of occurrences of holes with a given type.
+countHoles :: TypeRep -> Expr -> Int
+countHoles t = count t . holes
 
 -- | Number of occurrences of a given variable name.
 -- In term rewriting terms: |s|_x
diff --git a/tests/test-engine.hs b/tests/test-engine.hs
--- a/tests/test-engine.hs
+++ b/tests/test-engine.hs
@@ -82,6 +82,47 @@
   ,       subConsequence emptyThy [] (abs' xx -==- abs' yy) (abs' xx) (abs' yy)
   , not $ subConsequence emptyThy [] (abs' xx -<=- abs' yy) (abs' xx) (abs' yy)
   , not $ subConsequence emptyThy [] (abs' xx -==- one) (xx -+- abs' xx) zero
+
+  , holds n $ \e -> length (expansions preludeInstances 1 e) == 1
+
+  , expansions preludeInstances 2 (i_ -+- i_)
+    == [ xx -+- xx
+       , xx -+- yy
+       , yy -+- xx
+       , yy -+- yy ]
+
+  , expansions preludeInstances 2 (i_ -+- i_ -+- ord' c_)
+    == [ xx -+- xx -+- ord' cc
+       , xx -+- xx -+- ord' dd
+       , xx -+- yy -+- ord' cc
+       , xx -+- yy -+- ord' dd
+       , yy -+- xx -+- ord' cc
+       , yy -+- xx -+- ord' dd
+       , yy -+- yy -+- ord' cc
+       , yy -+- yy -+- ord' dd ]
+
+  , expansionsOfType intTy ["x","y"] (i_ -+- i_ -+- ord' c_)
+    == [ xx -+- xx -+- ord' c_
+       , xx -+- yy -+- ord' c_
+       , yy -+- xx -+- ord' c_
+       , yy -+- yy -+- ord' c_ ]
+
+  , expansionsOfType intTy [] (i_ -+- i_ -+- ord' c_) == []
+
+  , expansionsWith [xx, yy]     (i_ -+- i_ -+- ord' c_)
+    == [ xx -+- xx -+- ord' c_
+       , xx -+- yy -+- ord' c_
+       , yy -+- xx -+- ord' c_
+       , yy -+- yy -+- ord' c_ ]
+
+  , expansionsWith [cc]         (i_ -+- i_ -+- ord' c_)
+    == [ i_ -+- i_ -+- ord' cc ]
+
+  , expansionsWith [xx, yy, cc] (i_ -+- i_ -+- ord' c_)
+    == [ xx -+- xx -+- ord' cc
+       , xx -+- yy -+- ord' cc
+       , yy -+- xx -+- ord' cc
+       , yy -+- yy -+- ord' cc ]
   ]
   where
   x === y = equal preludeInstances 1000 x y
