diff --git a/bench/runtime/zero/bench/candidates.runtime b/bench/runtime/zero/bench/candidates.runtime
--- a/bench/runtime/zero/bench/candidates.runtime
+++ b/bench/runtime/zero/bench/candidates.runtime
@@ -1,1 +1,1 @@
-17.7
+18.1
diff --git a/bench/runtime/zero/bench/carry-on.runtime b/bench/runtime/zero/bench/carry-on.runtime
--- a/bench/runtime/zero/bench/carry-on.runtime
+++ b/bench/runtime/zero/bench/carry-on.runtime
@@ -1,1 +1,1 @@
-4.7
+4.9
diff --git a/bench/runtime/zero/bench/erroneous.runtime b/bench/runtime/zero/bench/erroneous.runtime
--- a/bench/runtime/zero/bench/erroneous.runtime
+++ b/bench/runtime/zero/bench/erroneous.runtime
@@ -1,1 +1,1 @@
-5.7
+6.1
diff --git a/bench/runtime/zero/bench/gps.runtime b/bench/runtime/zero/bench/gps.runtime
--- a/bench/runtime/zero/bench/gps.runtime
+++ b/bench/runtime/zero/bench/gps.runtime
@@ -1,1 +1,1 @@
-28.4
+28.1
diff --git a/bench/runtime/zero/bench/p30.runtime b/bench/runtime/zero/bench/p30.runtime
--- a/bench/runtime/zero/bench/p30.runtime
+++ b/bench/runtime/zero/bench/p30.runtime
@@ -1,1 +1,1 @@
-0.0
+0.1
diff --git a/bench/runtime/zero/bench/redundants.runtime b/bench/runtime/zero/bench/redundants.runtime
--- a/bench/runtime/zero/bench/redundants.runtime
+++ b/bench/runtime/zero/bench/redundants.runtime
@@ -1,1 +1,1 @@
-6.4
+6.6
diff --git a/bench/runtime/zero/bench/strategies.runtime b/bench/runtime/zero/bench/strategies.runtime
--- a/bench/runtime/zero/bench/strategies.runtime
+++ b/bench/runtime/zero/bench/strategies.runtime
@@ -1,1 +1,1 @@
-8.9
+9.4
diff --git a/bench/runtime/zero/bench/unique.runtime b/bench/runtime/zero/bench/unique.runtime
--- a/bench/runtime/zero/bench/unique.runtime
+++ b/bench/runtime/zero/bench/unique.runtime
@@ -1,1 +1,1 @@
-4.8
+4.9
diff --git a/bench/runtime/zero/eg/arith.runtime b/bench/runtime/zero/eg/arith.runtime
--- a/bench/runtime/zero/eg/arith.runtime
+++ b/bench/runtime/zero/eg/arith.runtime
@@ -1,1 +1,1 @@
-2.0
+1.9
diff --git a/bench/runtime/zero/eg/bits.runtime b/bench/runtime/zero/eg/bits.runtime
--- a/bench/runtime/zero/eg/bits.runtime
+++ b/bench/runtime/zero/eg/bits.runtime
@@ -1,1 +1,1 @@
-6.3
+5.9
diff --git a/bench/runtime/zero/eg/bools.runtime b/bench/runtime/zero/eg/bools.runtime
--- a/bench/runtime/zero/eg/bools.runtime
+++ b/bench/runtime/zero/eg/bools.runtime
@@ -1,1 +1,1 @@
-3.1
+3.0
diff --git a/bench/runtime/zero/eg/bst.runtime b/bench/runtime/zero/eg/bst.runtime
--- a/bench/runtime/zero/eg/bst.runtime
+++ b/bench/runtime/zero/eg/bst.runtime
@@ -1,1 +1,1 @@
-7.4
+9.0
diff --git a/bench/runtime/zero/eg/count.runtime b/bench/runtime/zero/eg/count.runtime
--- a/bench/runtime/zero/eg/count.runtime
+++ b/bench/runtime/zero/eg/count.runtime
@@ -1,1 +1,1 @@
-0.7
+1.0
diff --git a/bench/runtime/zero/eg/dupos.runtime b/bench/runtime/zero/eg/dupos.runtime
--- a/bench/runtime/zero/eg/dupos.runtime
+++ b/bench/runtime/zero/eg/dupos.runtime
@@ -1,1 +1,1 @@
-6.0
+3.6
diff --git a/bench/runtime/zero/eg/factorial.runtime b/bench/runtime/zero/eg/factorial.runtime
--- a/bench/runtime/zero/eg/factorial.runtime
+++ b/bench/runtime/zero/eg/factorial.runtime
@@ -1,1 +1,1 @@
-2.6
+2.5
diff --git a/bench/runtime/zero/eg/fibonacci.runtime b/bench/runtime/zero/eg/fibonacci.runtime
--- a/bench/runtime/zero/eg/fibonacci.runtime
+++ b/bench/runtime/zero/eg/fibonacci.runtime
@@ -1,1 +1,1 @@
-6.2
+6.1
diff --git a/bench/runtime/zero/eg/higher.runtime b/bench/runtime/zero/eg/higher.runtime
--- a/bench/runtime/zero/eg/higher.runtime
+++ b/bench/runtime/zero/eg/higher.runtime
@@ -1,1 +1,1 @@
-1.7
+1.6
diff --git a/bench/runtime/zero/eg/peano.runtime b/bench/runtime/zero/eg/peano.runtime
--- a/bench/runtime/zero/eg/peano.runtime
+++ b/bench/runtime/zero/eg/peano.runtime
@@ -1,1 +1,1 @@
-0.6
+0.5
diff --git a/bench/runtime/zero/eg/pow.runtime b/bench/runtime/zero/eg/pow.runtime
--- a/bench/runtime/zero/eg/pow.runtime
+++ b/bench/runtime/zero/eg/pow.runtime
@@ -1,1 +1,1 @@
-5.3
+5.0
diff --git a/bench/runtime/zero/eg/sort.runtime b/bench/runtime/zero/eg/sort.runtime
--- a/bench/runtime/zero/eg/sort.runtime
+++ b/bench/runtime/zero/eg/sort.runtime
@@ -1,1 +1,1 @@
-5.3
+5.9
diff --git a/bench/runtime/zero/eg/spec.runtime b/bench/runtime/zero/eg/spec.runtime
--- a/bench/runtime/zero/eg/spec.runtime
+++ b/bench/runtime/zero/eg/spec.runtime
@@ -1,1 +1,1 @@
-1.5
+1.7
diff --git a/bench/runtime/zero/eg/these.runtime b/bench/runtime/zero/eg/these.runtime
--- a/bench/runtime/zero/eg/these.runtime
+++ b/bench/runtime/zero/eg/these.runtime
@@ -1,1 +1,1 @@
-1.7
+1.6
diff --git a/bench/runtime/zero/eg/tree.runtime b/bench/runtime/zero/eg/tree.runtime
--- a/bench/runtime/zero/eg/tree.runtime
+++ b/bench/runtime/zero/eg/tree.runtime
@@ -1,1 +1,1 @@
-2.7
+2.8
diff --git a/bench/weird.hs b/bench/weird.hs
--- a/bench/weird.hs
+++ b/bench/weird.hs
@@ -39,6 +39,7 @@
   , prim "&&" (&&)
   , prim "||" (||)
   , prif (undefined :: Int)
+  -- guard does not play well with usePatterns = False yet
   ]
 
 -- | returns the sum when one of the arguments is 0
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -2,6 +2,13 @@
 ============================
 
 
+v0.6.8 (February 2025)
+----------------------
+
+* add `guard` to provide guard as a primitive
+* fix bug in `maxConstantSize` handling
+
+
 v0.6.6 (February 2025)
 ----------------------
 
diff --git a/code-conjure.cabal b/code-conjure.cabal
--- a/code-conjure.cabal
+++ b/code-conjure.cabal
@@ -3,7 +3,7 @@
 -- Copyright (C) 2021-2025 Rudy Matela
 -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
 name:                code-conjure
-version:             0.6.6
+version:             0.6.8
 synopsis:            synthesize Haskell functions out of partial definitions
 description:
   Conjure is a tool that synthesizes Haskell functions out of partial definitions.
@@ -69,7 +69,7 @@
 source-repository this
   type:            git
   location:        https://github.com/rudymatela/conjure
-  tag:             v0.6.6
+  tag:             v0.6.8
 
 library
   exposed-modules: Conjure
diff --git a/eg/bst.hs b/eg/bst.hs
--- a/eg/bst.hs
+++ b/eg/bst.hs
@@ -126,7 +126,7 @@
     , prim "||" (||)
     , prim "==" ((==) :: Int -> Int -> Bool)
     , prim "<" ((<) :: Int -> Int -> Bool)
-    , prif (undefined :: Bool)
+    , guard
     ]
 
   conjure "mem" mem
@@ -145,14 +145,16 @@
     , primOrdCaseFor (undefined :: Tree)
     ]
 
+  -- reachable in 15s after 32878 at size 14.
   -- out of reach performance-wise (reaching 16 but need 19)
   -- cf. the primOrdCaseFor version below
-  conjureFromSpecWith args{maxSize = 12} "before" beforeSpec
+  -- increase target to 50400 to reach...
+  conjureFromSpecWith args{target=10080} "before" beforeSpec
     [ pr Leaf
     , prim "Node" Node
     , prim "==" ((==) :: Int -> Int -> Bool)
     , prim "<" ((<) :: Int -> Int -> Bool)
-    , prif (undefined :: Tree)
+    , guard
     ]
 
   -- with 15, this reaches the solution, using 12 for shorter runtime
diff --git a/eg/bst.txt b/eg/bst.txt
--- a/eg/bst.txt
+++ b/eg/bst.txt
@@ -68,10 +68,11 @@
 -- 86 candidates of size 7
 -- 239 candidates of size 8
 -- 104 candidates of size 9
--- 1558 candidates of size 10
+-- 1342 candidates of size 10
 -- 3543 candidates of size 11
--- 4028 candidates of size 12
--- tested 9587 candidates
+-- 2552 candidates of size 12
+-- 23874 candidates of size 13
+-- tested 31769 candidates
 cannot conjure
 
 before :: Int -> Tree -> Tree
diff --git a/eg/count.hs b/eg/count.hs
--- a/eg/count.hs
+++ b/eg/count.hs
@@ -42,3 +42,13 @@
     , prim "==" ((==) :: A -> A -> Bool)
     , prif (undefined :: Int)
     ]
+
+  -- a little bit larger, guards are only allowed at the root
+  -- so there is a need to repeat the recursive call twice
+  conjure "count" count'
+    [ pr (0 :: Int)
+    , pr (1 :: Int)
+    , prim "+" ((+) :: Int -> Int -> Int)
+    , prim "==" ((==) :: A -> A -> Bool)
+    , guard
+    ]
diff --git a/eg/count.txt b/eg/count.txt
--- a/eg/count.txt
+++ b/eg/count.txt
@@ -27,3 +27,25 @@
 count x []  =  0
 count x (y:xs)  =  count x xs + (if x == y then 1 else 0)
 
+count :: A -> [A] -> Int
+-- testing 13 combinations of argument values
+-- pruning with 8/13 rules
+-- 2 candidates of size 1
+-- 0 candidates of size 2
+-- 0 candidates of size 3
+-- 0 candidates of size 4
+-- 0 candidates of size 5
+-- 4 candidates of size 6
+-- 0 candidates of size 7
+-- 12 candidates of size 8
+-- 16 candidates of size 9
+-- 20 candidates of size 10
+-- 20 candidates of size 11
+-- 44 candidates of size 12
+-- 64 candidates of size 13
+-- tested 127 candidates
+count x []  =  0
+count x (y:xs)
+  | x == y  =  count x xs + 1
+  | otherwise  =  count x xs
+
diff --git a/eg/dupos.hs b/eg/dupos.hs
--- a/eg/dupos.hs
+++ b/eg/dupos.hs
@@ -58,7 +58,7 @@
     , prim "&&" (&&)
     , prim ":" ((:) :: Int -> [Int] -> [Int])
     , prim "elem" (elem :: Int -> [Int] -> Bool)
-    , prif (undefined :: [Int])
+    , guard
     ]
 
   conjureFromSpec "duplicates" duplicatesSpec
@@ -67,7 +67,7 @@
     , prim "&&" (&&)
     , prim ":" ((:) :: Int -> [Int] -> [Int])
     , prim "elem" (elem :: Int -> [Int] -> Bool)
-    , prif (undefined :: [Int])
+    , guard
     ]
 
   conjure "positionsFrom" positionsFrom'
diff --git a/eg/dupos.txt b/eg/dupos.txt
--- a/eg/dupos.txt
+++ b/eg/dupos.txt
@@ -10,19 +10,19 @@
 -- 1 candidates of size 7
 -- 6 candidates of size 8
 -- 5 candidates of size 9
--- 22 candidates of size 10
--- 15 candidates of size 11
--- 48 candidates of size 12
--- 93 candidates of size 13
--- 188 candidates of size 14
--- 505 candidates of size 15
--- 706 candidates of size 16
--- 1723 candidates of size 17
--- tested 1705 candidates
+-- 16 candidates of size 10
+-- 11 candidates of size 11
+-- 26 candidates of size 12
+-- 23 candidates of size 13
+-- 52 candidates of size 14
+-- 49 candidates of size 15
+-- 78 candidates of size 16
+-- 75 candidates of size 17
+-- tested 271 candidates
 duplicates []  =  []
-duplicates (x:xs)  =  if elem x xs && not (elem x (duplicates xs))
-                      then x:duplicates xs
-                      else duplicates xs
+duplicates (x:xs)
+  | elem x xs && not (elem x (duplicates xs))  =  x:duplicates xs
+  | otherwise  =  duplicates xs
 
 duplicates :: [Int] -> [Int]
 -- pruning with 21/26 rules
@@ -34,20 +34,20 @@
 -- 2 candidates of size 6
 -- 3 candidates of size 7
 -- 8 candidates of size 8
--- 15 candidates of size 9
--- 24 candidates of size 10
--- 35 candidates of size 11
--- 62 candidates of size 12
--- 129 candidates of size 13
--- 282 candidates of size 14
--- 559 candidates of size 15
--- 1036 candidates of size 16
--- 1899 candidates of size 17
--- tested 2274 candidates
+-- 13 candidates of size 9
+-- 18 candidates of size 10
+-- 21 candidates of size 11
+-- 28 candidates of size 12
+-- 39 candidates of size 13
+-- 54 candidates of size 14
+-- 67 candidates of size 15
+-- 80 candidates of size 16
+-- 99 candidates of size 17
+-- tested 340 candidates
 duplicates []  =  []
-duplicates (x:xs)  =  if elem x xs && not (elem x (duplicates xs))
-                      then x:duplicates xs
-                      else duplicates xs
+duplicates (x:xs)
+  | elem x xs && not (elem x (duplicates xs))  =  x:duplicates xs
+  | otherwise  =  duplicates xs
 
 positionsFrom :: Int -> A -> [A] -> [Int]
 -- testing 360 combinations of argument values
diff --git a/eg/fib01.hs b/eg/fib01.hs
--- a/eg/fib01.hs
+++ b/eg/fib01.hs
@@ -28,7 +28,7 @@
   -- are particularly hard for conjure to synthesize.
   -- I've added an item in TODO.md to address this in 2025-02.
 
-  -- It takes about 33 seconds to run with maxSize=8
+  -- Found!  It takes about 12 seconds to run with maxSize=8
   -- running with maxSize = 5 for faster runtime
   conjureWith args{maxSize=5, maxConstantSize=1} "fib01" fib01
     [ pr (0::Int)
diff --git a/eg/higher.hs b/eg/higher.hs
--- a/eg/higher.hs
+++ b/eg/higher.hs
@@ -49,5 +49,5 @@
 primitives  =
   [ pr ([] :: [Int])
   , prim ":" ((:) :: Int -> [Int] -> [Int])
-  , prif (undefined :: [Int])
+  , guard
   ]
diff --git a/eg/higher.txt b/eg/higher.txt
--- a/eg/higher.txt
+++ b/eg/higher.txt
@@ -56,14 +56,14 @@
 -- 0 candidates of size 5
 -- 5 candidates of size 6
 -- 0 candidates of size 7
--- 17 candidates of size 8
+-- 15 candidates of size 8
 -- 0 candidates of size 9
--- 43 candidates of size 10
+-- 21 candidates of size 10
 -- 0 candidates of size 11
--- 141 candidates of size 12
--- tested 71 candidates
+-- 33 candidates of size 12
+-- tested 47 candidates
 filter f []  =  []
-filter f (x:xs)  =  if f x
-                    then x:filter f xs
-                    else filter f xs
+filter f (x:xs)
+  | f x  =  x:filter f xs
+  | otherwise  =  filter f xs
 
diff --git a/eg/list.hs b/eg/list.hs
--- a/eg/list.hs
+++ b/eg/list.hs
@@ -82,7 +82,7 @@
     [ pr ([] :: [Int])
     , prim ":" ((:) :: Int -> [Int] -> [Int])
     , prim "null" (null :: [Int] -> Bool)
-    , prif (undefined :: Int)
+    , guard
     , prim "undefined" (undefined :: Int)
     ]
 
diff --git a/eg/list.txt b/eg/list.txt
--- a/eg/list.txt
+++ b/eg/list.txt
@@ -59,9 +59,9 @@
 -- 4 candidates of size 7
 -- tested 2 candidates
 last []  =  undefined
-last (x:xs)  =  if null xs
-                then x
-                else last xs
+last (x:xs)
+  | null xs  =  x
+  | otherwise  =  last xs
 
 zip :: [Int] -> [Int] -> [(Int,Int)]
 -- testing 360 combinations of argument values
diff --git a/eg/sort.hs b/eg/sort.hs
--- a/eg/sort.hs
+++ b/eg/sort.hs
@@ -37,6 +37,9 @@
 merge' [0,1] [0,1]  =  [0,0,1,1]
 merge' [0,1] [2,3]  =  [0,1,2,3]
 merge' [0,2] [1,3]  =  [0,1,2,3]
+merge' [0,1] [1,2]  =  [0,1,1,2]
+merge' [1,2] [0,1]  =  [0,1,1,2]
+merge' [0,2] [1,1]  =  [0,1,1,2]
 
 main :: IO ()
 main = do
@@ -64,7 +67,7 @@
     [ prim "[]" ([] :: [Int])
     , prim ":" ((:) :: Int -> [Int] -> [Int])
     , prim "<=" ((<=) :: Int -> Int -> Bool)
-    , prif (undefined :: [Int])
+    , guard
     ]
 
   -- qsort []  =  []                           -- 1
@@ -93,16 +96,18 @@
     , prim "filter" (filter :: (Int -> Bool) -> [Int] -> [Int])
     ]
 
-  -- merge [] []  =  []
-  -- merge (x:xs) (y:ys)  =  if x <= y then x:merge xs (y:ys) else y:merge (x:xs) ys
-  --                         2  3 4  5      678     9 10 11 12  13 14 15 16 17 18 19
-  -- OOM after size 17, out of reach performance wise
-  -- update: cannot reach at size 19 on lapmatrud OOM
-  conjureWith args{target=1080} "merge" merge'
+  -- found!  candidate #1703311 @ size 22
+  -- merge [] xs  =  xs
+  -- merge (x:xs) []  =  x:xs
+  -- merge (x:xs) (y:ys)
+  --   | x <= y  =  x:merge xs (y:ys)
+  --   | otherwise  =  merge (y:x:xs) ys
+  -- set target to 2 000 000 to reach it
+  conjureWith args{target=10080, maxTests=1080} "merge" merge'
     [ pr ([] :: [Int])
     , prim ":" ((:) :: Int -> [Int] -> [Int])
     , prim "<=" ((<=) :: Int -> Int -> Bool)
-    , prif (undefined :: [Int])
+    , guard
     ]
 
   -- unreachable: needs about 26, but can only reach 16
diff --git a/eg/sort.txt b/eg/sort.txt
--- a/eg/sort.txt
+++ b/eg/sort.txt
@@ -35,16 +35,16 @@
 -- 8 candidates of size 10
 -- 18 candidates of size 11
 -- 16 candidates of size 12
--- 102 candidates of size 13
+-- 70 candidates of size 13
 -- 32 candidates of size 14
--- 426 candidates of size 15
--- 224 candidates of size 16
--- 1450 candidates of size 17
--- tested 991 candidates
+-- 226 candidates of size 15
+-- 64 candidates of size 16
+-- 602 candidates of size 17
+-- tested 519 candidates
 insert x []  =  [x]
-insert x (y:xs)  =  if x <= y
-                    then x:insert y xs
-                    else y:insert x xs
+insert x (y:xs)
+  | x <= y  =  x:insert y xs
+  | otherwise  =  y:insert x xs
 
 qsort :: [Int] -> [Int]
 -- testing 360 combinations of argument values
@@ -89,7 +89,7 @@
 qsort (x:xs)  =  qsort (filter (x >) xs) ++ (x:qsort (filter (x <=) xs))
 
 merge :: [Int] -> [Int] -> [Int]
--- testing 360 combinations of argument values
+-- testing 1080 combinations of argument values
 -- pruning with 4/4 rules
 -- 3 candidates of size 1
 -- 0 candidates of size 2
@@ -102,8 +102,11 @@
 -- 114 candidates of size 9
 -- 36 candidates of size 10
 -- 472 candidates of size 11
--- 604 candidates of size 12
--- tested 1290 candidates
+-- 568 candidates of size 12
+-- 1442 candidates of size 13
+-- 4204 candidates of size 14
+-- 5426 candidates of size 15
+-- tested 12326 candidates
 cannot conjure
 
 merge :: [Int] -> [Int] -> [Int]
diff --git a/eg/these.hs b/eg/these.hs
--- a/eg/these.hs
+++ b/eg/these.hs
@@ -80,7 +80,7 @@
     , prim ":" ((:) :: A -> [A] -> [A])
     , prim "isThis" (isThis :: These A B -> Bool)
     , prim "fromThis" (fromThis :: These A B -> A)
-    , prif (undefined :: [A])
+    , guard
     ]
 
   conjure "cathat" cathat'
@@ -88,7 +88,7 @@
     , prim ":" ((:) :: B -> [B] -> [B])
     , prim "isThat" (isThat :: These A B -> Bool)
     , prim "fromThat" (fromThat :: These A B -> B)
-    , prif (undefined :: [B])
+    , guard
     ]
 
   -- couldn't make this reachable, I didn't try much...
@@ -101,7 +101,8 @@
     , prim "isThat" (isThat :: These A A -> Bool)
     , prim "fromThat" (fromThat :: These A A -> A)
     -- , prif (undefined :: A)
-    , prif (undefined :: [A])
+    -- , prif (undefined :: [A])
+    , guard
     ]
   -- expected functionality
   -- these []  =  []
diff --git a/eg/these.txt b/eg/these.txt
--- a/eg/these.txt
+++ b/eg/these.txt
@@ -48,13 +48,13 @@
 -- 2 candidates of size 7
 -- 0 candidates of size 8
 -- 1 candidates of size 9
--- 6 candidates of size 10
--- 6 candidates of size 11
--- tested 12 candidates
+-- 4 candidates of size 10
+-- 2 candidates of size 11
+-- tested 10 candidates
 cathis []  =  []
-cathis (t:ts)  =  if isThis t
-                  then fromThis t:cathis ts
-                  else cathis ts
+cathis (t:ts)
+  | isThis t  =  fromThis t:cathis ts
+  | otherwise  =  cathis ts
 
 cathat :: [These A B] -> [B]
 -- testing 4 combinations of argument values
@@ -68,13 +68,13 @@
 -- 2 candidates of size 7
 -- 0 candidates of size 8
 -- 1 candidates of size 9
--- 6 candidates of size 10
--- 6 candidates of size 11
--- tested 12 candidates
+-- 4 candidates of size 10
+-- 2 candidates of size 11
+-- tested 10 candidates
 cathat []  =  []
-cathat (t:ts)  =  if isThat t
-                  then fromThat t:cathat ts
-                  else cathat ts
+cathat (t:ts)
+  | isThat t  =  fromThat t:cathat ts
+  | otherwise  =  cathat ts
 
 cathese :: [These A A] -> [A]
 -- testing 5 combinations of argument values
@@ -88,12 +88,15 @@
 -- 4 candidates of size 7
 -- 2 candidates of size 8
 -- 9 candidates of size 9
--- 36 candidates of size 10
--- 38 candidates of size 11
--- 75 candidates of size 12
--- 224 candidates of size 13
--- 422 candidates of size 14
--- 753 candidates of size 15
--- tested 1567 candidates
+-- 20 candidates of size 10
+-- 22 candidates of size 11
+-- 35 candidates of size 12
+-- 84 candidates of size 13
+-- 86 candidates of size 14
+-- 137 candidates of size 15
+-- 324 candidates of size 16
+-- 346 candidates of size 17
+-- 511 candidates of size 18
+-- tested 1584 candidates
 cannot conjure
 
diff --git a/src/Conjure.hs b/src/Conjure.hs
--- a/src/Conjure.hs
+++ b/src/Conjure.hs
@@ -97,6 +97,7 @@
   , Prim
   , pr
   , prim
+  , guard
   , prif
   , primOrdCaseFor
 
diff --git a/src/Conjure/Conjurable.hs b/src/Conjure/Conjurable.hs
--- a/src/Conjure/Conjurable.hs
+++ b/src/Conjure/Conjurable.hs
@@ -35,6 +35,7 @@
   , conjureReification1
   , conjureDynamicEq
   , conjureIsNumeric
+  , conjureGuard
   , cevaluate
   , ceval
   , cevl
@@ -443,6 +444,10 @@
 -- | Checks if an 'Expr' is of an unbreakable type.
 conjureIsUnbreakable :: Conjurable f => f -> Expr -> Bool
 conjureIsUnbreakable f  =  null . conjureCasesFor f
+
+-- | Conjures a guard at the return type of the given function.
+conjureGuard :: Conjurable f => f -> Expr
+conjureGuard  =  ifToGuard . conjureIf
 
 instance Conjurable () where
   conjureExpress   =  reifyExpress
diff --git a/src/Conjure/Defn.hs b/src/Conjure/Defn.hs
--- a/src/Conjure/Defn.hs
+++ b/src/Conjure/Defn.hs
@@ -71,6 +71,9 @@
   where
   show1 (lhs,rhs)  =
     case rhs of
+    (Value "|" _ :$ c :$ t :$ e) -> showExpr lhs
+                         ++ "\n  | " ++ showExpr c ++ "  =  " ++ showExpr t
+                         ++ "\n  | otherwise  =  " ++ showExpr e
     (Value "if" _ :$ c :$ t :$ e) -> lhseqs ++ "if " ++ showExpr c
                           ++ "\n" ++ spaces ++ "then " ++ showExpr t
                           ++ "\n" ++ spaces ++ "else " ++ showExpr e
diff --git a/src/Conjure/Engine.hs b/src/Conjure/Engine.hs
--- a/src/Conjure/Engine.hs
+++ b/src/Conjure/Engine.hs
@@ -502,12 +502,16 @@
   pats | maxPatternSize > 0  =  take maxPatternSize $ conjurePats es nm f
        | otherwise           =                        conjurePats es nm f
   fss  =  concatMapT ps2fss pats
-  es  =  map fst ps
+  -- replaces the any guard symbol with a guard of the correct type
+  es  =  [if isGuardSymbol e then conjureGuard f else e | (e,_) <- ps]
 
   eh  =  holeAsTypeOf efxs
   efxs  =  conjureVarApplication nm f
   (ef:_)  =  unfoldApp efxs
 
+  unguardT | any isGuardSymbol es  =  discardT isGuard
+           | otherwise             =  id
+
   keep | rewriting  =  isRootNormalC thy . fastMostGeneralVariation
        | otherwise  =  const True
 
@@ -517,13 +521,13 @@
   appsWith :: Expr -> [Expr] -> [[Expr]]
   appsWith eh vs  =  enumerateAppsFor eh k $ vs ++ es
     where
-    k | atomicNumbers && isNumeric eh  =  \e -> keepNumeric e && keep e
-      | maxConstantSize > 0            =  \e -> keepConstant e && keep e
-      | otherwise                      =  keep
+    k e  =  keepNumeric e && keepConstant e && keep e
     -- discards non-atomic numeric ground expressions such as 1 + 1
-    keepNumeric e  =  isFun e || isConst e || not (isGround e)
+    keepNumeric | atomicNumbers && isNumeric eh  =  \e -> isFun e || isConst e || not (isGround e)
+                | otherwise                      =  const True
     -- discards big non-atomic ground expressions such as 1 + 1 or reverse [1,2]
-    keepConstant e  =  isFun e || isConst e || not (isGround e) || size e <= maxConstantSize
+    keepConstant | maxConstantSize > 0  =  \e -> isFun e || isConst e || not (isGround e) || size e <= maxConstantSize
+                 | otherwise            =  const True
 
   isRedundant | adHocRedundancy  =  \e -> isRedundantDefn e || isRedundantModuloRewriting (normalize thy) e
               | otherwise        =  const False
@@ -604,6 +608,7 @@
   deconstructions  =  filter (conjureIsDeconstruction f maxTests)
                    $  concatMap candidateDeconstructionsFromHoled
                    $  concat . take maxDeconstructionSize
+                   $  unguardT
                    $  concatMapT (`appsWith` hs) [hs]
     where
     hs  =  nub $ conjureArgumentHoles f
@@ -612,7 +617,7 @@
            .  discardT (\e -> e == ep)
            $  recsV' (tail (vars ep))
   recsV vs  =  filterT (\e -> any (`elem` vs) (vars e))
-            $  foldAppProducts ef [appsWith h vs | h <- conjureArgumentHoles f]
+            $  foldAppProducts ef [unguardT $ appsWith h vs | h <- conjureArgumentHoles f]
   -- like recs, but memoized
   recs' ep  =  fromMaybe errRP $ lookup ep eprs
     where
diff --git a/src/Conjure/Expr.hs b/src/Conjure/Expr.hs
--- a/src/Conjure/Expr.hs
+++ b/src/Conjure/Expr.hs
@@ -19,6 +19,8 @@
   , compareSimplicity
   , ifFor
   , caseForOrd
+  , guardFor
+  , ifToGuard
   , valuesBFS
   , holesBFS
   , fillBFS
@@ -34,6 +36,9 @@
   , isZero
   , isNegative
   , isStrictSubexprOf
+  , isGuardSymbol
+  , isGuard
+  , hasGuard
 
   , enumerateAppsFor
   , enumerateFillings
@@ -203,6 +208,7 @@
 -- This currently works by checking if the function is an if, '&&' or '||'.
 mayNotEvaluateArgument :: Expr -> Bool
 mayNotEvaluateArgument (Value "if" ce :$ _ :$ _)  =  True
+mayNotEvaluateArgument (Value "|"  ce :$ _ :$ _)  =  True
 mayNotEvaluateArgument (Value "&&" ce :$ _)       =  True
 mayNotEvaluateArgument (Value "||" ce :$ _)       =  True
 mayNotEvaluateArgument _                          =  False
@@ -227,6 +233,27 @@
 caseForOrd :: Typeable a => a -> Expr
 caseForOrd a  =  value "case" (\o x y z -> case o of LT -> x; EQ -> y; GT -> z `asTypeOf` a)
 
+-- | Creates an if 'Expr' of the type argument of the given proxy.
+--
+-- The expression is named as @|@ as if to represent a guard.
+--
+-- > > guardFor (undefined :: Int)
+-- > (|) :: Bool -> Int -> Int -> Int
+--
+-- In the future, maybe we display these differently in Conjure as guards.
+--
+-- For now, this will signalize an if that can only appear as a root expression.
+guardFor :: Typeable a => a -> Expr
+guardFor a  =  value "|" (\p x y -> if p then x else y `asTypeOf` a)
+
+-- | Changes an if encoded as an 'Expr' to a guard encoded as an 'Expr'.
+--
+-- This works for both the dangling symbol, or for a full application.
+ifToGuard :: Expr -> Expr
+ifToGuard (Value "if" dyn)  =  Value "|" dyn
+ifToGuard (Value "if" dyn :$ ep :$ ex :$ ey)  =  Value "|" dyn :$ ep :$ ex :$ ey
+ifToGuard e  =  e
+
 -- | Lists terminal values in BFS order.
 --
 -- (cf. 'values', 'holesBFS', 'fillBFS')
@@ -346,12 +373,15 @@
   for h  =  filter (\e -> typ h == typ e) es : apps
     where
     apps  =  foldr (\/) []
-          [  filterT keep $ fliproductWith (:$) (for hf) (for hx)
+          [  filterT keep $ fliproductWith (:$) (ufor hf) (ufor hx)
           |  hf <- hs
           ,  hx <- hs
           ,  Just hfx <- [hf $$ hx]
           ,  typ h == typ hfx
           ]
+  -- unguarded for
+  ufor | any isGuardSymbol es  =  filterT (not . isGuard) . for
+       | otherwise             =  for
 
 -- | Given an expression whose holes are /all of the same type/
 --   and an enumeration of 'Expr's of this same type,
@@ -386,6 +416,11 @@
     Nothing    -> Nothing
     Just (m,n,True)  -> re m n ex
     Just (m,n,False) -> re m n ey
+  -- the following repeats the above
+  re m n (Value "|" _ :$ ec :$ ex :$ ey)  =  case rev m n ec of
+    Nothing    -> Nothing
+    Just (m,n,True)  -> re m n ex
+    Just (m,n,False) -> re m n ey
   re m n (Value "||" _ :$ ep :$ eq)  =  case rev m n ep of
     Nothing        -> Nothing
     Just (m,n,True)  -> (m,n,) <$> toDynamic (val True)
@@ -552,6 +587,24 @@
 isNegative :: Expr -> Bool
 isNegative (Value ('-':_) _)  =  True
 isNegative _  =  False
+
+isGuardSymbol :: Expr -> Bool
+isGuardSymbol (Value "|" _)  =  True
+isGuardSymbol _  =  False
+
+-- | Is the expression a guard application?
+isGuard :: Expr -> Bool
+isGuard (Value "|" _ :$ _ :$ _ :$ _)  =  True
+isGuard _  =  False
+
+-- | Has this expression a non-root guard?
+--
+-- This only checks the immediate sub-expressions,
+-- good enough for when enumerating.
+--
+-- Guards at the root are still allowed.
+hasGuard :: Expr -> Bool
+hasGuard (ef :$ ex)  =  isGuard ef || isGuard ex
 
 -- | Lists all variables in an expression
 --   that are of the same type of the expression itself.
diff --git a/src/Conjure/Prim.hs b/src/Conjure/Prim.hs
--- a/src/Conjure/Prim.hs
+++ b/src/Conjure/Prim.hs
@@ -15,6 +15,7 @@
   , pr
   , prif
   , primOrdCaseFor
+  , guard
   , cjHoles
   , cjTiersFor
   , cjAreEqual
@@ -98,6 +99,43 @@
 -- >                 else last xs
 prif :: Conjurable a => a -> Prim
 prif x  =  (ifFor x, conjureType x)
+
+
+-- | Provides an if condition bound to the conjured function's return type.
+--
+-- Guards are only alllowed at the root fo the RHS.
+--
+-- > last' :: [Int] -> Int
+-- > last' [x]  =  x
+-- > last' [x,y]  =  y
+-- > last' [x,y,z]  =  z
+--
+-- > > conjure "last" last'
+-- > >   [ pr ([] :: [Int])
+-- > >   , prim ":" ((:) :: Int -> [Int] -> [Int])
+-- > >   , prim "null" (null :: [Int] -> Bool)
+-- > >   , guard
+-- > >   , prim "undefined" (undefined :: Int)
+-- > >   ]
+-- > last :: [Int] -> Int
+-- > -- 0.0s, testing 360 combinations of argument values
+-- > -- 0.0s, pruning with 5/5 rules
+-- > -- 0.0s, 1 candidates of size 1
+-- > -- 0.0s, 0 candidates of size 2
+-- > -- 0.0s, 0 candidates of size 3
+-- > -- 0.0s, 0 candidates of size 4
+-- > -- 0.0s, 0 candidates of size 5
+-- > -- 0.0s, 0 candidates of size 6
+-- > -- 0.0s, 4 candidates of size 7
+-- > -- 0.0s, tested 2 candidates
+-- > last []  =  undefined
+-- > last (x:xs)
+-- >   | null xs  =  x
+-- >   | otherwise  =  last xs
+guard :: Prim
+guard  =  (guardFor (undefined :: Bool), conjureType (undefined :: Bool))
+-- internally we always return a guard of the Bool return type,
+-- this is replaced by Conjure when enumerating candidates
 
 
 -- | Provides a case condition bound to the given return type.
