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 +1/−1
- bench/runtime/zero/bench/carry-on.runtime +1/−1
- bench/runtime/zero/bench/erroneous.runtime +1/−1
- bench/runtime/zero/bench/gps.runtime +1/−1
- bench/runtime/zero/bench/p30.runtime +1/−1
- bench/runtime/zero/bench/redundants.runtime +1/−1
- bench/runtime/zero/bench/strategies.runtime +1/−1
- bench/runtime/zero/bench/unique.runtime +1/−1
- bench/runtime/zero/eg/arith.runtime +1/−1
- bench/runtime/zero/eg/bits.runtime +1/−1
- bench/runtime/zero/eg/bools.runtime +1/−1
- bench/runtime/zero/eg/bst.runtime +1/−1
- bench/runtime/zero/eg/count.runtime +1/−1
- bench/runtime/zero/eg/dupos.runtime +1/−1
- bench/runtime/zero/eg/factorial.runtime +1/−1
- bench/runtime/zero/eg/fibonacci.runtime +1/−1
- bench/runtime/zero/eg/higher.runtime +1/−1
- bench/runtime/zero/eg/peano.runtime +1/−1
- bench/runtime/zero/eg/pow.runtime +1/−1
- bench/runtime/zero/eg/sort.runtime +1/−1
- bench/runtime/zero/eg/spec.runtime +1/−1
- bench/runtime/zero/eg/these.runtime +1/−1
- bench/runtime/zero/eg/tree.runtime +1/−1
- bench/weird.hs +1/−0
- changelog.md +7/−0
- code-conjure.cabal +2/−2
- eg/bst.hs +5/−3
- eg/bst.txt +4/−3
- eg/count.hs +10/−0
- eg/count.txt +22/−0
- eg/dupos.hs +2/−2
- eg/dupos.txt +25/−25
- eg/fib01.hs +1/−1
- eg/higher.hs +1/−1
- eg/higher.txt +7/−7
- eg/list.hs +1/−1
- eg/list.txt +3/−3
- eg/sort.hs +13/−8
- eg/sort.txt +14/−11
- eg/these.hs +4/−3
- eg/these.txt +22/−19
- src/Conjure.hs +1/−0
- src/Conjure/Conjurable.hs +5/−0
- src/Conjure/Defn.hs +3/−0
- src/Conjure/Engine.hs +12/−7
- src/Conjure/Expr.hs +54/−1
- src/Conjure/Prim.hs +38/−0
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.