packages feed

code-conjure 0.6.6 → 0.6.8

raw patch · 47 files changed

+280/−120 lines, 47 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Conjure: guard :: Prim
+ Conjure.Conjurable: conjureGuard :: Conjurable f => f -> Expr
+ Conjure.Expr: guardFor :: Typeable a => a -> Expr
+ Conjure.Expr: hasGuard :: Expr -> Bool
+ Conjure.Expr: ifToGuard :: Expr -> Expr
+ Conjure.Expr: isGuard :: Expr -> Bool
+ Conjure.Expr: isGuardSymbol :: Expr -> Bool
+ Conjure.Prim: guard :: Prim

Files

bench/runtime/zero/bench/candidates.runtime view
@@ -1,1 +1,1 @@-17.7+18.1
bench/runtime/zero/bench/carry-on.runtime view
@@ -1,1 +1,1 @@-4.7+4.9
bench/runtime/zero/bench/erroneous.runtime view
@@ -1,1 +1,1 @@-5.7+6.1
bench/runtime/zero/bench/gps.runtime view
@@ -1,1 +1,1 @@-28.4+28.1
bench/runtime/zero/bench/p30.runtime view
@@ -1,1 +1,1 @@-0.0+0.1
bench/runtime/zero/bench/redundants.runtime view
@@ -1,1 +1,1 @@-6.4+6.6
bench/runtime/zero/bench/strategies.runtime view
@@ -1,1 +1,1 @@-8.9+9.4
bench/runtime/zero/bench/unique.runtime view
@@ -1,1 +1,1 @@-4.8+4.9
bench/runtime/zero/eg/arith.runtime view
@@ -1,1 +1,1 @@-2.0+1.9
bench/runtime/zero/eg/bits.runtime view
@@ -1,1 +1,1 @@-6.3+5.9
bench/runtime/zero/eg/bools.runtime view
@@ -1,1 +1,1 @@-3.1+3.0
bench/runtime/zero/eg/bst.runtime view
@@ -1,1 +1,1 @@-7.4+9.0
bench/runtime/zero/eg/count.runtime view
@@ -1,1 +1,1 @@-0.7+1.0
bench/runtime/zero/eg/dupos.runtime view
@@ -1,1 +1,1 @@-6.0+3.6
bench/runtime/zero/eg/factorial.runtime view
@@ -1,1 +1,1 @@-2.6+2.5
bench/runtime/zero/eg/fibonacci.runtime view
@@ -1,1 +1,1 @@-6.2+6.1
bench/runtime/zero/eg/higher.runtime view
@@ -1,1 +1,1 @@-1.7+1.6
bench/runtime/zero/eg/peano.runtime view
@@ -1,1 +1,1 @@-0.6+0.5
bench/runtime/zero/eg/pow.runtime view
@@ -1,1 +1,1 @@-5.3+5.0
bench/runtime/zero/eg/sort.runtime view
@@ -1,1 +1,1 @@-5.3+5.9
bench/runtime/zero/eg/spec.runtime view
@@ -1,1 +1,1 @@-1.5+1.7
bench/runtime/zero/eg/these.runtime view
@@ -1,1 +1,1 @@-1.7+1.6
bench/runtime/zero/eg/tree.runtime view
@@ -1,1 +1,1 @@-2.7+2.8
bench/weird.hs view
@@ -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
changelog.md view
@@ -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) ---------------------- 
code-conjure.cabal view
@@ -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
eg/bst.hs view
@@ -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
eg/bst.txt view
@@ -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
eg/count.hs view
@@ -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+    ]
eg/count.txt view
@@ -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+
eg/dupos.hs view
@@ -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'
eg/dupos.txt view
@@ -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
eg/fib01.hs view
@@ -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)
eg/higher.hs view
@@ -49,5 +49,5 @@ primitives  =   [ pr ([] :: [Int])   , prim ":" ((:) :: Int -> [Int] -> [Int])-  , prif (undefined :: [Int])+  , guard   ]
eg/higher.txt view
@@ -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 
eg/list.hs view
@@ -82,7 +82,7 @@     [ pr ([] :: [Int])     , prim ":" ((:) :: Int -> [Int] -> [Int])     , prim "null" (null :: [Int] -> Bool)-    , prif (undefined :: Int)+    , guard     , prim "undefined" (undefined :: Int)     ] 
eg/list.txt view
@@ -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
eg/sort.hs view
@@ -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
eg/sort.txt view
@@ -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]
eg/these.hs view
@@ -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 []  =  []
eg/these.txt view
@@ -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 
src/Conjure.hs view
@@ -97,6 +97,7 @@   , Prim   , pr   , prim+  , guard   , prif   , primOrdCaseFor 
src/Conjure/Conjurable.hs view
@@ -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
src/Conjure/Defn.hs view
@@ -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
src/Conjure/Engine.hs view
@@ -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
src/Conjure/Expr.hs view
@@ -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.
src/Conjure/Prim.hs view
@@ -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.