code-conjure 0.5.0 → 0.5.2
raw patch · 52 files changed
+631/−54 lines, 52 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Conjure: [uniqueCandidates] :: Args -> Bool
+ Conjure.Conjurable: conjureDynamicEq :: Conjurable f => f -> Dynamic
+ Conjure.Engine: [uniqueCandidates] :: Args -> Bool
+ Conjure.Engine: grounds :: (Expr -> [[Expr]]) -> Expr -> [Expr]
+ Conjure.Utils: foldr0 :: (a -> a -> a) -> a -> [a] -> a
- Conjure: Args :: Int -> Int -> Int -> Int -> Int -> Int -> Bool -> Bool -> Bool -> Args
+ Conjure: Args :: Int -> Int -> Int -> Int -> Int -> Int -> Bool -> Bool -> Bool -> Bool -> Args
- Conjure.Engine: Args :: Int -> Int -> Int -> Int -> Int -> Int -> Bool -> Bool -> Bool -> Args
+ Conjure.Engine: Args :: Int -> Int -> Int -> Int -> Int -> Int -> Bool -> Bool -> Bool -> Bool -> Args
Files
- .github/workflows/build.yml +2/−2
- Makefile +1/−1
- README.md +62/−10
- TODO.md +1/−3
- bench/gps.hs +20/−5
- bench/gps.out +62/−0
- bench/gps2.hs +2/−1
- bench/gps2.out +32/−0
- bench/ill-hit.out +2/−0
- bench/lowtests.out +4/−0
- bench/p12.out +1/−0
- bench/runtime/zero/bench/candidates.runtime +1/−1
- bench/runtime/zero/bench/gps.runtime +1/−1
- bench/runtime/zero/bench/ill-hit.runtime +1/−1
- bench/runtime/zero/bench/terpret.runtime +1/−1
- bench/runtime/zero/eg/arith.runtime +1/−1
- bench/runtime/zero/eg/count.runtime +1/−1
- bench/runtime/zero/eg/dupos.runtime +1/−1
- bench/runtime/zero/eg/fib01.runtime +1/−1
- bench/runtime/zero/versions +1/−1
- bench/self.out +4/−0
- bench/take-drop.out +2/−0
- bench/terpret.hs +1/−0
- bench/terpret.out +11/−0
- changelog.md +10/−0
- code-conjure.cabal +2/−2
- eg/arith.hs +13/−0
- eg/arith.out +26/−0
- eg/bools.out +4/−0
- eg/count.out +2/−0
- eg/dupos.out +3/−0
- eg/factorial.out +2/−0
- eg/fib01.out +2/−0
- eg/fibonacci.out +1/−0
- eg/gcd.out +1/−0
- eg/ints.out +6/−0
- eg/list.out +7/−0
- eg/pow.out +2/−0
- eg/replicate.out +4/−0
- eg/setelem.out +2/−0
- eg/sort.out +4/−0
- eg/spec.out +4/−0
- eg/subset.out +2/−0
- eg/tapps.out +3/−0
- eg/tree.out +6/−0
- src/Conjure/Conjurable.hs +9/−0
- src/Conjure/Conjurable/Derive.hs +69/−4
- src/Conjure/Engine.hs +36/−14
- src/Conjure/Utils.hs +6/−0
- stack.yaml +1/−1
- test/conjurable.hs +84/−2
- test/derive.hs +104/−0
.github/workflows/build.yml view
@@ -111,8 +111,8 @@ steps: - name: Setup Haskell's GHC and Cabal as required by current Stackage LTS uses: haskell/actions/setup@v1- with: # lts-17.9- ghc-version: '8.10.4'+ with: # lts-18.14+ ghc-version: '8.10.7' cabal-version: '3.2' - uses: actions/cache@v2
Makefile view
@@ -1,5 +1,5 @@ GHCIMPORTDIRS = src:test-GHCFLAGS = -O2 \+GHCFLAGS = -O2 -v0 \ $(shell grep -q "Arch Linux" /etc/lsb-release && echo -dynamic) HADDOCKFLAGS = \ -i $(shell find ~/.cabal -name express.haddock | tail -1) \
README.md view
@@ -17,11 +17,7 @@ To install the [latest Conjure version from Hackage], just run: $ cabal update- $ cabal v1-install code-conjure--If you are using Cabal v3.0 or later,-[avoid using `cabal install`] for the time being-and use `v1-install` instead.+ $ cabal install code-conjure Prerequisites are [express], [leancheck] and [speculate]. They should be automatically resolved and installed by [Cabal].@@ -29,7 +25,21 @@ NOTE: the name of the Hackage package is __[`code-conjure`]__ -- not to be confused with [Conjure the BitTorrent client]. +Starting from Cabal v3.0, you need to pass `--lib` as an argument to+`cabal install` to install packages globally on the `default` user environment: + $ cabal install code-conjure --lib++If you already have Conjure installed+[Cabal may refuse to update](https://github.com/haskell/cabal/issues/7373)+to the latest version.+To update, you need to reset your user's cabal installation with:++ rm -rf ~/.cabal/{bin,lib,logs,share,store} ~/.ghc/*/++WARNING: the above command will erase all user-local packages.++ Synthesizing functions ---------------------- @@ -293,17 +303,61 @@ Related work ------------ +__Conjure's dependencies__.+Internally, Conjure uses [LeanCheck], [Speculate] and [Express].+[LeanCheck] does testing similarly to [QuickCheck], [SmallCheck] or [Feat].+[Speculate] discovers equations similarly to [QuickSpec].+[Express] encodes expressions involving [Dynamic] types.++[Speculate]: https://github.com/rudymatela/speculate+[Express]: https://github.com/rudymatela/express+[QuickCheck]: https://hackage.haskell.org/package/QuickCheck+[smallcheck]: https://hackage.haskell.org/package/smallcheck+[Feat]: https://hackage.haskell.org/package/testing-feat+[QuickSpec]: https://hackage.haskell.org/package/quickspec+[Dynamic]: https://hackage.haskell.org/package/base/docs/Data-Dynamic.html+++__Program synthesis within Haskell.__++[MagicHaskeller]: https://hackage.haskell.org/package/MagicHaskeller+[Igor II]: https://cogsys.uni-bamberg.de/projects/effalip+ [MagicHaskeller] (2007) is another tool that is able to generate Haskell code automatically. It supports recursion through catamorphisms, paramorphisms and the [`fix`] function.+[Igor II] (2010) is able to synthesize Haskell+programs as well. -[Barliman] for Lisp is another tool that does program synthesis.+[Hoogle]: https://hoogle.haskell.org/+[Hoogle+]: https://hoogleplus.goto.ucsd.edu/ -There are hundreds of others,-I'll add the most closely related here when I have the time.+[Hoogle] (2004) is a search engine for Haskell functions.+It is not able to synthesize expressions+but it can find functions that match a type.+[Hoogle+] (2020) is similar to Hoogle+but is able to search for small expressions.+In addition to the type, Hoogle+ allows+users to provide tests that the function should pass. +__Program synthesis beyond Haskell.__++[PushGP]: https://github.com/lspector/Clojush+[G3P]: https://github.com/t-h-e/HeuristicLab.CFGGP++[PushGP] (2002) and [G3P] (2017) are genetic programming systems +that are able to synthesize programs in Push and Python respectively.+Differently from Conjure or MagicHaskeller,+they require around a hundred tests for traning+instead of just about half a dozen.++[Barliman]: https://github.com/webyrd/Barliman++[Barliman] (2016) for Lisp is another tool that does program synthesis.++ Further reading --------------- @@ -343,8 +397,6 @@ [LeanCheck]: https://hackage.haskell.org/package/leancheck [express]: https://hackage.haskell.org/package/express [speculate]: https://hackage.haskell.org/package/speculate-[MagicHaskeller]: https://hackage.haskell.org/package/MagicHaskeller-[Barliman]: https://github.com/webyrd/Barliman [avoid using `cabal install`]: https://github.com/haskell/cabal/issues/7373 [latest Conjure version from Hackage]: https://hackage.haskell.org/package/code-conjure
TODO.md view
@@ -3,9 +3,7 @@ A non-exhaustive list of things TO DO for Conjure. -* derive `conjureCases`, `conjureSize` and `conjureSubTypes`;--* implement `deriveConjurable` using TH (cf. `deriveExpress` and `deriveGeneralizable`);+* test `conjureCases` from `deriveConjurable`; * consider not breaking in some cases (increased crossproduct of patterns)
bench/gps.hs view
@@ -321,6 +321,15 @@ , prif (undefined :: Rational) ] + -- simplified background+ conjure "wallisNext" wallisNextP+ [ pr (0 :: Integer)+ , pr (1 :: Integer)+ , prim "+" ((+) :: Integer -> Integer -> Integer)+ , prim "*" ((*) :: Integer -> Integer -> Integer)+ , prim "%" ((%) :: Integer -> Integer -> Rational)+ ]+ conjure "gps10" gps10p [ pr (2 :: Integer) , pr (3 :: Integer)@@ -829,11 +838,17 @@ -- Conjure found a smaller implementation! gps27c :: IO ()-gps27c = conjure "gps27" gps27p- [ prim "<" ((<) :: Int -> Int -> Bool)- , prim "&&" (&&)- , prif (undefined :: Int)- ]+gps27c = do+ conjure "gps27" gps27p+ [ prim "<" ((<) :: Int -> Int -> Bool)+ , prim "&&" (&&)+ , prif (undefined :: Int)+ ]++ conjure "gps27b" gps27p+ [ prim "min" (min :: Int -> Int -> Int)+ , prim "max" (max :: Int -> Int -> Int)+ ] -- GPS Benchmark #28 -- Smallest --
bench/gps.out view
@@ -5,6 +5,7 @@ -- looking through 1 candidates of size 2 -- looking through 1 candidates of size 3 -- looking through 2 candidates of size 4+-- tested 4 candidates gps1 x y = fromIntegral x + y gps2 :: Int -> Maybe [Char]@@ -23,6 +24,7 @@ -- looking through 176 candidates of size 11 -- looking through 704 candidates of size 12 -- looking through 1856 candidates of size 13+-- tested 1744 candidates gps2 x = if 2000 <= x then Just "large" else (if x < 1000 then Just "small" else Nothing) gps3 :: Int -> Int -> Int -> [Int]@@ -36,6 +38,7 @@ -- looking through 1536 candidates of size 6 -- looking through 0 candidates of size 7 -- looking through 26991 candidates of size 8+-- tested 19480 candidates gps3 x y z = enumFromThenTo x (x + z) (y - 1) gps3 :: Int -> Int -> Int -> [Int]@@ -49,6 +52,7 @@ -- looking through 0 candidates of size 6 -- looking through 108 candidates of size 7 -- looking through 36 candidates of size 8+-- tested 166 candidates cannot conjure gps4 :: [Char] -> [Char] -> [Char] -> Bool@@ -65,6 +69,7 @@ -- looking through 162 candidates of size 9 -- looking through 30 candidates of size 10 -- looking through 30 candidates of size 11+-- tested 201 candidates gps4 cs ds es = length cs < length ds && length ds < length es gps5 :: [Char] -> [Char]@@ -76,6 +81,7 @@ -- looking through 6 candidates of size 4 -- looking through 5 candidates of size 5 -- looking through 13 candidates of size 6+-- tested 30 candidates cannot conjure gps6 :: Int -> Int@@ -87,6 +93,7 @@ -- looking through 146 candidates of size 4 -- looking through 624 candidates of size 5 -- looking through 2576 candidates of size 6+-- tested 3392 candidates cannot conjure gps7 :: [Char] -> ([Char],Int)@@ -103,6 +110,7 @@ -- looking through 88 candidates of size 9 -- looking through 201 candidates of size 10 -- looking through 442 candidates of size 11+-- tested 546 candidates gps7 cs = (init (unlines (words cs)),length (filter (not . isSpace) cs)) gps8 :: [Char] -> [Char] -> [(Int,Char,Char)]@@ -111,6 +119,7 @@ -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2 -- looking through 0 candidates of size 3+-- tested 0 candidates cannot conjure gps9 :: Int -> [Int]@@ -126,6 +135,7 @@ -- looking through 83 candidates of size 8 -- looking through 143 candidates of size 9 -- looking through 259 candidates of size 10+-- tested 328 candidates gps9 x = filter even (filter (x >) (map sq [1..x])) wallisNext :: Ratio Integer -> Ratio Integer@@ -139,8 +149,23 @@ -- looking through 118 candidates of size 6 -- looking through 5 candidates of size 7 -- looking through 1001 candidates of size 8+-- tested 1015 candidates wallisNext (x % y) = (y + 1) % (x + 1) +wallisNext :: Ratio Integer -> Ratio Integer+-- testing 6 combinations of argument values+-- pruning with 15/26 rules+-- looking through 1 candidates of size 1+-- looking through 0 candidates of size 2+-- looking through 4 candidates of size 3+-- looking through 16 candidates of size 4+-- looking through 3 candidates of size 5+-- looking through 103 candidates of size 6+-- looking through 5 candidates of size 7+-- looking through 801 candidates of size 8+-- tested 832 candidates+wallisNext (x % y) = (y + 1) % (x + 1)+ gps10 :: Int -> Ratio Integer -- testing 6 combinations of argument values -- pruning with 3/4 rules@@ -152,6 +177,7 @@ -- looking through 5 candidates of size 6 -- looking through 8 candidates of size 7 -- looking through 13 candidates of size 8+-- tested 33 candidates gps10 x = product (take x (iterate wallisNext (2 % 3))) gps11 :: [[Char]] -> [Int]@@ -161,6 +187,7 @@ -- looking through 0 candidates of size 2 -- looking through 1 candidates of size 3 -- looking through 1 candidates of size 4+-- tested 2 candidates gps11 css = reverse (map length css) gps11 :: [[Char]] -> [Int]@@ -174,6 +201,7 @@ -- looking through 2 candidates of size 6 -- looking through 0 candidates of size 7 -- looking through 2 candidates of size 8+-- tested 6 candidates gps11 [] = [] gps11 (cs:css) = gps11 css ++ [length cs] @@ -191,6 +219,7 @@ -- looking through 1166 candidates of size 9 -- looking through 3187 candidates of size 10 -- looking through 9282 candidates of size 11+-- tested 10413 candidates gps12 xs = (length xs - fromJust (findIndex (0 ==) (reverse xs))) - 1 gps13 :: [Ratio Integer] -> Ratio Integer@@ -204,6 +233,7 @@ -- looking through 56 candidates of size 6 -- looking through 125 candidates of size 7 -- looking through 449 candidates of size 8+-- tested 317 candidates gps13 qs = foldr (+) 0 qs / fromIntegral (length qs) odd :: Int -> Bool@@ -214,6 +244,7 @@ -- looking through 7 candidates of size 3 -- looking through 0 candidates of size 4 -- looking through 71 candidates of size 5+-- tested 17 candidates odd x = x `mod` 2 /= 0 gps14 :: [Int] -> Int@@ -223,6 +254,7 @@ -- looking through 1 candidates of size 2 -- looking through 0 candidates of size 3 -- looking through 1 candidates of size 4+-- tested 2 candidates gps14 xs = length (filter odd xs) gps14 :: [Int] -> Int@@ -235,6 +267,7 @@ -- looking through 66 candidates of size 5 -- looking through 600 candidates of size 6 -- looking through 1034 candidates of size 7+-- tested 749 candidates gps14 [] = 0 gps14 (x:xs) = x `mod` 2 + gps14 xs @@ -245,6 +278,7 @@ -- looking through 0 candidates of size 2 -- looking through 2 candidates of size 3 -- looking through 8 candidates of size 4+-- tested 4 candidates gps15 xs ys = reverse xs == ys gps16 :: [Char] -> [Char] -> Bool@@ -255,6 +289,7 @@ -- looking through 2 candidates of size 3 -- looking through 6 candidates of size 4 -- looking through 2 candidates of size 5+-- tested 9 candidates gps16 cs ds = sort cs `isSubsequenceOf` sort ds gps17 :: Int -> Int@@ -269,6 +304,7 @@ -- looking through 577 candidates of size 7 -- looking through 1311 candidates of size 8 -- looking through 5282 candidates of size 9+-- tested 2201 candidates gps17 0 = 0 gps17 x = x * x + gps17 (x - 1) @@ -284,6 +320,7 @@ -- looking through 791 candidates of size 7 -- looking through 220 candidates of size 8 -- looking through 4632 candidates of size 9+-- tested 3931 candidates gps18 [] [] = [] gps18 [] (x:xs) = xs gps18 (x:xs) [] = xs@@ -296,6 +333,7 @@ -- looking through 2 candidates of size 2 -- looking through 0 candidates of size 3 -- looking through 12 candidates of size 4+-- tested 14 candidates gps18 xs ys = zipWith (+) xs ys gps19 :: Int -> [Char] -> [Char]@@ -303,6 +341,7 @@ -- pruning with 0/0 rules -- looking through 1 candidates of size 1 -- looking through 0 candidates of size 2+-- tested 1 candidates cannot conjure isVowel :: Char -> Bool@@ -330,6 +369,7 @@ -- looking through 62 candidates of size 20 -- looking through 62 candidates of size 21 -- looking through 126 candidates of size 22+-- tested 1207 candidates isVowel 'a' = True isVowel 'e' = True isVowel 'i' = True@@ -354,6 +394,7 @@ -- looking through 3495 candidates of size 12 -- looking through 6382 candidates of size 13 -- looking through 20409 candidates of size 14+-- tested 27901 candidates pig1 "" = "ay" pig1 (c:cs) = if isVowel c then (c:cs) ++ "ay" else cs ++ (c:"ay") @@ -364,6 +405,7 @@ -- looking through 2 candidates of size 3 -- looking through 3 candidates of size 4 -- looking through 5 candidates of size 5+-- tested 12 candidates gps20c cs = unwords (map pig1 (words cs)) gps21 :: [Int] -> [Int]@@ -379,6 +421,7 @@ -- looking through 30 candidates of size 8 -- looking through 25 candidates of size 9 -- looking through 65 candidates of size 10+-- tested 96 candidates gps21 [] = [] gps21 (x:xs) = (if x < 0 then 0 else x):gps21 xs @@ -390,6 +433,7 @@ -- looking through 0 candidates of size 4 -- looking through 0 candidates of size 5 -- looking through 4 candidates of size 6+-- tested 5 candidates gps22 "" = 0 gps22 (c:cs) = scrabble1 c + gps22 cs @@ -398,6 +442,7 @@ -- pruning with 0/0 rules -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2+-- tested 0 candidates cannot conjure gps24 :: [Char] -> Char@@ -413,12 +458,14 @@ -- looking through 97 candidates of size 8 -- looking through 286 candidates of size 9 -- looking through 739 candidates of size 10+-- tested 673 candidates gps24 cs = chr (ord ' ' + sum (map ord cs) `mod` 64) gps25 :: Int -> [Int] -- testing 4 combinations of argument values -- pruning with 0/0 rules -- looking through 0 candidates of size 1+-- tested 0 candidates cannot conjure gps26 :: Int -> Int -> Int -> Int -> Int -> Char@@ -426,6 +473,7 @@ -- pruning with 4/4 rules -- looking through 5 candidates of size 1 -- looking through 0 candidates of size 2+-- tested 5 candidates cannot conjure gps27 :: Int -> Int -> Int -> Int@@ -442,8 +490,20 @@ -- looking through 0 candidates of size 9 -- looking through 180 candidates of size 10 -- looking through 2592 candidates of size 11+-- tested 1579 candidates gps27 x y z = if x < y then (if y < z then y else z) else x +gps27b :: Int -> Int -> Int -> Int+-- testing 3 combinations of argument values+-- pruning with 20/30 rules+-- looking through 3 candidates of size 1+-- looking through 0 candidates of size 2+-- looking through 12 candidates of size 3+-- looking through 0 candidates of size 4+-- looking through 36 candidates of size 5+-- tested 16 candidates+gps27b x y z = min (max x y) z+ gps28 :: Int -> Int -> Int -> Int -> Int -- testing 5 combinations of argument values -- pruning with 6/10 rules@@ -454,6 +514,7 @@ -- looking through 24 candidates of size 5 -- looking through 0 candidates of size 6 -- looking through 72 candidates of size 7+-- tested 44 candidates gps28 x y z x' = x `min` (y `min` (z `min` x')) gps29 :: [Char] -> Int@@ -467,6 +528,7 @@ -- looking through 18 candidates of size 7 -- looking through 33 candidates of size 8 -- looking through 65 candidates of size 9+-- tested 86 candidates gps29 "" = 0 gps29 (c:cs) = (if isVowel c then 1 else 0) + gps29 cs
bench/gps2.hs view
@@ -482,7 +482,8 @@ -- can generate at size 15 in 18 seconds--- setting limit of 5 for faster output+-- setting limit of 5 for faster automated tests+-- BENCHMARK: increase maxSize from 5 to 18 gps17c :: IO () gps17c = conjureWith args{maxSize=5} "gps17_pds" gps17p [ pr (0 :: Int)
bench/gps2.out view
@@ -11,6 +11,7 @@ -- looking through 0 candidates of size 8 -- looking through 1 candidates of size 9 -- looking through 2 candidates of size 10+-- tested 5 candidates gps1 xs = findIndex (0 >) (map (foldr (+) 0) (tail (inits xs))) gps1 :: [Int] -> Maybe Int@@ -24,6 +25,7 @@ -- looking through 0 candidates of size 6 -- looking through 1 candidates of size 7 -- looking through 4 candidates of size 8+-- tested 6 candidates gps1 xs = findIndex (0 >) (map sum (tail (inits xs))) gps1 :: Int -> [Int] -> Int@@ -33,6 +35,7 @@ -- looking through 25 candidates of size 2 -- looking through 255 candidates of size 3 -- looking through 451 candidates of size 4+-- tested 735 candidates cannot conjure gps2 :: Double -> Double -> Int -> Double@@ -44,12 +47,14 @@ -- looking through 70 candidates of size 4 -- looking through 314 candidates of size 5 -- looking through 1432 candidates of size 6+-- tested 1838 candidates cannot conjure gps3 :: [Char] -> Int -- pruning with 0/0 rules -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2+-- tested 0 candidates cannot conjure gps4 :: [Char] -> [Char]@@ -60,12 +65,14 @@ -- looking through 22 candidates of size 4 -- looking through 54 candidates of size 5 -- looking through 124 candidates of size 6+-- tested 214 candidates cannot conjure gps5 :: Int -> [Int] -- testing 6 combinations of argument values -- pruning with 0/0 rules -- looking through 0 candidates of size 1+-- tested 0 candidates cannot conjure tell :: [Int] -> Int -> [Int]@@ -80,6 +87,7 @@ -- looking through 538 candidates of size 8 -- looking through 134 candidates of size 9 -- looking through 5299 candidates of size 10+-- tested 2699 candidates tell [] x = [] tell (x:xs) y = y `div` x:tell xs (y `mod` x) @@ -89,6 +97,7 @@ -- looking through 1 candidates of size 1 -- looking through 0 candidates of size 2 -- looking through 1 candidates of size 3+-- tested 2 candidates gps5 x = tell [25,10,5,1] x gps5 :: Int -> [Int]@@ -105,6 +114,7 @@ -- looking through 4450 candidates of size 9 -- looking through 9710 candidates of size 10 -- looking through 44767 candidates of size 11+-- tested 32953 candidates gps5 x = tell [25,10,5,1] x gps6 :: [Int] -> Int@@ -112,12 +122,14 @@ -- pruning with 0/0 rules -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2+-- tested 0 candidates cannot conjure gps7 :: Integer -> Integer -> Ratio Integer -- testing 6 combinations of argument values -- pruning with 0/0 rules -- looking through 0 candidates of size 1+-- tested 0 candidates cannot conjure gps :: Int -> [Int] -> (Int,Int)@@ -125,18 +137,21 @@ -- pruning with 0/0 rules -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2+-- tested 0 candidates cannot conjure gps :: Int -> [Char] -- testing 7 combinations of argument values -- pruning with 0/0 rules -- looking through 0 candidates of size 1+-- tested 0 candidates cannot conjure gps :: Int -> [Char] -- testing 7 combinations of argument values -- pruning with 0/0 rules -- looking through 0 candidates of size 1+-- tested 0 candidates cannot conjure gcd :: Int -> Int -> Int@@ -148,6 +163,7 @@ -- looking through 60 candidates of size 4 -- looking through 150 candidates of size 5 -- looking through 472 candidates of size 6+-- tested 246 candidates gcd x 0 = x gcd x y = gcd y (x `mod` y) @@ -159,6 +175,7 @@ -- looking through 0 candidates of size 3 -- looking through 0 candidates of size 4 -- looking through 4 candidates of size 5+-- tested 3 candidates gps12 cs ds = findIndices (ds `isPrefixOf`) (tails cs) gps13_leaders :: [Int] -> [Int]@@ -176,6 +193,7 @@ -- looking through 21 candidates of size 10 -- looking through 34 candidates of size 11 -- looking through 67 candidates of size 12+-- tested 83 candidates gps13_leaders [] = [] gps13_leaders (x:xs) = if all (x >) xs then x:gps13_leaders xs else gps13_leaders xs @@ -183,11 +201,13 @@ -- pruning with 0/0 rules -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2+-- tested 0 candidates cannot conjure gps15_mastermind :: () -> () -- pruning with 0/1 rules -- looking through 1 candidates of size 1+-- tested 1 candidates gps15_mastermind u = u gps16_middle :: [Char] -> [Char]@@ -205,6 +225,7 @@ -- looking through 824 candidates of size 10 -- looking through 2282 candidates of size 11 -- looking through 6293 candidates of size 12+-- tested 3977 candidates gps16_middle "" = "" gps16_middle (c:cs) = if length cs <= 1 then c:cs else gps16_middle (init cs) @@ -216,6 +237,7 @@ -- looking through 2 candidates of size 3 -- looking through 1 candidates of size 4 -- looking through 5 candidates of size 5+-- tested 11 candidates cannot conjure gps18_price :: [Double] -> [Double] -> Double@@ -227,6 +249,7 @@ -- looking through 72 candidates of size 4 -- looking through 1192 candidates of size 5 -- looking through 696 candidates of size 6+-- tested 2042 candidates cannot conjure gps19_snowday :: Int -> Double -> Double -> Double -> Double@@ -238,12 +261,14 @@ -- looking through 169 candidates of size 4 -- looking through 543 candidates of size 5 -- looking through 3608 candidates of size 6+-- tested 4361 candidates cannot conjure gps20 :: [Char] -> Bool -- pruning with 0/0 rules -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2+-- tested 0 candidates cannot conjure spin :: [Char] -> [Char]@@ -257,6 +282,7 @@ -- looking through 0 candidates of size 6 -- looking through 0 candidates of size 7 -- looking through 4 candidates of size 8+-- tested 3 candidates spin cs = if length cs >= 5 then reverse cs else cs gps21_spinwords :: [Char] -> [Char]@@ -267,6 +293,7 @@ -- looking through 2 candidates of size 3 -- looking through 3 candidates of size 4 -- looking through 5 candidates of size 5+-- tested 12 candidates gps21_spinwords cs = unwords (map spin (words cs)) digits :: Int -> [Int]@@ -284,11 +311,13 @@ -- looking through 935 candidates of size 10 -- looking through 9018 candidates of size 11 -- looking through 9686 candidates of size 12+-- tested 20746 candidates cannot conjure gps22 :: Int -> [Char] -- pruning with 0/0 rules -- looking through 0 candidates of size 1+-- tested 0 candidates cannot conjure gps23 :: [Char] -> [Char] -> [Char] -> [Char]@@ -305,6 +334,7 @@ -- looking through 0 candidates of size 10 -- looking through 0 candidates of size 11 -- looking through 5184 candidates of size 12+-- tested 9174 candidates cannot conjure gps24 :: [Char] -> Twitter@@ -322,6 +352,7 @@ -- looking through 232 candidates of size 10 -- looking through 322 candidates of size 11 -- looking through 483 candidates of size 12+-- tested 936 candidates gps24 "" = Empty gps24 (c:cs) = if 140 > length cs then Tweet (length (c:cs)) else TooMany @@ -334,5 +365,6 @@ -- looking through 312 candidates of size 4 -- looking through 2262 candidates of size 5 -- looking through 9400 candidates of size 6+-- tested 12074 candidates cannot conjure
bench/ill-hit.out view
@@ -6,6 +6,7 @@ -- looking through 6 candidates of size 3 -- looking through 20 candidates of size 4 -- looking through 34 candidates of size 5+-- tested 34 candidates sum [] = 0 sum (x:xs) = x + sum xs @@ -16,6 +17,7 @@ -- looking through 6 candidates of size 3 -- looking through 20 candidates of size 4 -- looking through 34 candidates of size 5+-- tested 34 candidates sum [] = 0 sum (x:xs) = x + sum xs
bench/lowtests.out view
@@ -21,6 +21,7 @@ -- looking through 0 candidates of size 10 -- looking through 0 candidates of size 11 -- looking through 0 candidates of size 12+-- tested 48 candidates cannot conjure subset :: [Int] -> [Int] -> Bool@@ -38,6 +39,7 @@ -- looking through 2 candidates of size 3 -- looking through 6 candidates of size 4 -- looking through 2 candidates of size 5+-- tested 9 candidates subset xs ys = sort xs `isSubsequenceOf` sort ys replicates :: [Char] -> Int -> [Char]@@ -61,6 +63,7 @@ -- looking through 1 candidates of size 10 -- looking through 0 candidates of size 11 -- looking through 0 candidates of size 12+-- tested 4 candidates cannot conjure replicates :: [Char] -> Int -> [Char]@@ -77,5 +80,6 @@ -- looking through 0 candidates of size 3 -- looking through 1 candidates of size 4 -- looking through 1 candidates of size 5+-- tested 3 candidates replicates cs x = concat (transpose (replicate x cs))
bench/p12.out view
@@ -8,6 +8,7 @@ -- looking through 82 candidates of size 4 -- looking through 263 candidates of size 5 -- looking through 960 candidates of size 6+-- tested 406 candidates factorial 0 = 1 factorial x = x * factorial (dec x)
bench/runtime/zero/bench/candidates.runtime view
@@ -1,1 +1,1 @@-9.2+9.3
bench/runtime/zero/bench/gps.runtime view
@@ -1,1 +1,1 @@-22.8+23.8
bench/runtime/zero/bench/ill-hit.runtime view
@@ -1,1 +1,1 @@-0.9+0.8
bench/runtime/zero/bench/terpret.runtime view
@@ -1,1 +1,1 @@-13.2+13.3
bench/runtime/zero/eg/arith.runtime view
@@ -1,1 +1,1 @@-1.2+1.8
bench/runtime/zero/eg/count.runtime view
@@ -1,1 +1,1 @@-0.5+0.6
bench/runtime/zero/eg/dupos.runtime view
@@ -1,1 +1,1 @@-3.1+4.5
bench/runtime/zero/eg/fib01.runtime view
@@ -1,1 +1,1 @@-4.5+4.4
bench/runtime/zero/versions view
@@ -1,4 +1,4 @@ GHC 8.10.5 leancheck-0.9.10-express-1.0.6+express-1.0.8 speculate-0.4.14
bench/self.out view
@@ -4,6 +4,7 @@ -- looking through 4 candidates of size 1 -- looking through 18 candidates of size 2 -- looking through 120 candidates of size 3+-- tested 24 candidates x ? y = x + y (?) :: Int -> Int -> Int@@ -12,6 +13,7 @@ -- looking through 4 candidates of size 1 -- looking through 18 candidates of size 2 -- looking through 120 candidates of size 3+-- tested 40 candidates x ? y = x * y i :: Int -> Int@@ -20,6 +22,7 @@ -- looking through 3 candidates of size 1 -- looking through 4 candidates of size 2 -- looking through 22 candidates of size 3+-- tested 10 candidates i x = x + 1 d :: Int -> Int@@ -28,5 +31,6 @@ -- looking through 3 candidates of size 1 -- looking through 4 candidates of size 2 -- looking through 22 candidates of size 3+-- tested 29 candidates cannot conjure
bench/take-drop.out view
@@ -10,6 +10,7 @@ -- looking through 132 candidates of size 7 -- looking through 127 candidates of size 8 -- looking through 458 candidates of size 9+-- tested 495 candidates drop 0 [] = [] drop 0 (x:xs) = x:xs drop x [] = []@@ -27,6 +28,7 @@ -- looking through 132 candidates of size 7 -- looking through 127 candidates of size 8 -- looking through 458 candidates of size 9+-- tested 484 candidates take 0 [] = [] take 0 (x:xs) = [] take x [] = []
bench/terpret.hs view
@@ -137,6 +137,7 @@ -- using primitives123 below works, but increases the runtime to 18 seconds -- let's leave it commented out so runtime is faster when running automated tests+ -- BENCHMARK: uncomment primitives123 conjure "fadder" t5p $ -- primitives123 ++ [ prim "not" not , prim "," ((,) :: Bool -> Bool -> (Bool,Bool))
bench/terpret.out view
@@ -9,6 +9,7 @@ -- looking through 10 candidates of size 4 -- looking through 17 candidates of size 5 -- looking through 41 candidates of size 6+-- tested 36 candidates invert [] = [] invert (p:ps) = not p:invert ps @@ -20,6 +21,7 @@ -- looking through 2 candidates of size 1 -- looking through 1 candidates of size 2 -- looking through 5 candidates of size 3+-- tested 5 candidates prependZero ps = False:ps TerpreT benchmark #3: binary decrement@@ -36,6 +38,7 @@ -- looking through 86 candidates of size 7 -- looking through 202 candidates of size 8 -- looking through 487 candidates of size 9+-- tested 418 candidates decrement [] = [] decrement (p:ps) = not p:(if p then ps else decrement ps) @@ -56,6 +59,7 @@ -- looking through 8154 candidates of size 9 -- looking through 27432 candidates of size 10 -- looking through 174839 candidates of size 11+-- tested 137576 candidates cshift (p,q,r) = if p then (p,r,q) else (p,q,r) cshift :: Bool -> Bool -> Bool -> (Bool,Bool,Bool)@@ -70,6 +74,7 @@ -- looking through 1035 candidates of size 6 -- looking through 2457 candidates of size 7 -- looking through 20250 candidates of size 8+-- tested 22191 candidates cshift False p q = (False,p,q) cshift True p q = (True,q,p) @@ -89,6 +94,7 @@ -- looking through 2148 candidates of size 9 -- looking through 5520 candidates of size 10 -- looking through 13656 candidates of size 11+-- tested 16290 candidates fadder p q r = if p == q then (p,r) else (r,not r) TerpreT benchmark #6: 2-bit adder@@ -103,6 +109,7 @@ -- looking through 8 candidates of size 4 -- looking through 128 candidates of size 5 -- looking through 408 candidates of size 6+-- tested 544 candidates cannot conjure TerpreT benchmark #7: access@@ -113,6 +120,7 @@ -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2 -- looking through 1 candidates of size 3+-- tested 1 candidates xs `access` x = xs !! x access :: [A] -> Int -> A@@ -125,6 +133,7 @@ -- looking through 19 candidates of size 5 -- looking through 23 candidates of size 6 -- looking through 68 candidates of size 7+-- tested 67 candidates [] `access` 0 = undefined [] `access` x = undefined (x:xs) `access` 0 = x@@ -142,6 +151,7 @@ -- looking through 9 candidates of size 5 -- looking through 29 candidates of size 6 -- looking through 41 candidates of size 7+-- tested 53 candidates decrelements [] = [] decrelements (x:xs) = x - 1:decrelements xs @@ -152,5 +162,6 @@ -- looking through 1 candidates of size 2 -- looking through 3 candidates of size 3 -- looking through 8 candidates of size 4+-- tested 8 candidates decrelements xs = map (subtract 1) xs
changelog.md view
@@ -2,6 +2,16 @@ ============================ +0.5.2+-----++* show number of tested candidates+* complete `Conjurable` derivation functions+* reference related work on README+* add switch to unique-modulo-testing candidates (slow)+ to allow computing the near upper/lower limit on pruning++ v0.5.0 ------
code-conjure.cabal view
@@ -3,7 +3,7 @@ -- Copyright (C) 2021 Rudy Matela -- Distributed under the 3-Clause BSD licence (see the file LICENSE). name: code-conjure-version: 0.5.0+version: 0.5.2 synopsis: synthesize Haskell functions out of partial definitions description: Conjure is a tool that synthesizes Haskell functions out of partial definitions.@@ -63,7 +63,7 @@ source-repository this type: git location: https://github.com/rudymatela/conjure- tag: v0.5.0+ tag: v0.5.2 library exposed-modules: Conjure
eg/arith.hs view
@@ -10,6 +10,12 @@ double 2 = 4 double 3 = 6 +triple :: Int -> Int+triple 0 = 0+triple 1 = 3+triple 2 = 6+triple 3 = 9+ add :: Int -> Int -> Int add 0 0 = 0 add 0 1 = 1@@ -21,6 +27,11 @@ square 1 = 1 square 2 = 4 +cube :: Int -> Int+cube 0 = 0+cube 1 = 1+cube 2 = 8+ tnpo :: Int -> Int tnpo 0 = 1 tnpo 1 = 4@@ -29,8 +40,10 @@ main :: IO () main = do conjure "double" double primitives+ conjure "triple" triple primitives conjure "add" add primitives conjure "square" square primitives+ conjure "cube" cube primitives conjure "tnpo" tnpo primitives primitives :: [Prim]
eg/arith.out view
@@ -4,14 +4,27 @@ -- looking through 3 candidates of size 1 -- looking through 4 candidates of size 2 -- looking through 9 candidates of size 3+-- tested 8 candidates double x = x + x +triple :: Int -> Int+-- testing 4 combinations of argument values+-- pruning with 14/25 rules+-- looking through 3 candidates of size 1+-- looking through 4 candidates of size 2+-- looking through 9 candidates of size 3+-- looking through 23 candidates of size 4+-- looking through 29 candidates of size 5+-- tested 43 candidates+triple x = x + (x + x)+ add :: Int -> Int -> Int -- testing 4 combinations of argument values -- pruning with 14/25 rules -- looking through 4 candidates of size 1 -- looking through 18 candidates of size 2 -- looking through 101 candidates of size 3+-- tested 24 candidates add x y = x + y square :: Int -> Int@@ -20,8 +33,20 @@ -- looking through 3 candidates of size 1 -- looking through 4 candidates of size 2 -- looking through 9 candidates of size 3+-- tested 12 candidates square x = x * x +cube :: Int -> Int+-- testing 3 combinations of argument values+-- pruning with 14/25 rules+-- looking through 3 candidates of size 1+-- looking through 4 candidates of size 2+-- looking through 9 candidates of size 3+-- looking through 23 candidates of size 4+-- looking through 29 candidates of size 5+-- tested 55 candidates+cube x = x * (x * x)+ tnpo :: Int -> Int -- testing 3 combinations of argument values -- pruning with 14/25 rules@@ -32,5 +57,6 @@ -- looking through 29 candidates of size 5 -- looking through 71 candidates of size 6 -- looking through 113 candidates of size 7+-- tested 163 candidates tnpo x = x + (x + (x + 1))
eg/bools.out view
@@ -6,6 +6,7 @@ -- looking through 12 candidates of size 3 -- looking through 16 candidates of size 4 -- looking through 42 candidates of size 5+-- tested 45 candidates and [] = True and (p:ps) = p && and ps @@ -17,6 +18,7 @@ -- looking through 12 candidates of size 3 -- looking through 16 candidates of size 4 -- looking through 42 candidates of size 5+-- tested 39 candidates or [] = False or (p:ps) = p || or ps @@ -27,6 +29,7 @@ -- looking through 6 candidates of size 2 -- looking through 12 candidates of size 3 -- looking through 18 candidates of size 4+-- tested 28 candidates and ps = foldr (&&) True ps or :: [Bool] -> Bool@@ -36,5 +39,6 @@ -- looking through 6 candidates of size 2 -- looking through 12 candidates of size 3 -- looking through 18 candidates of size 4+-- tested 27 candidates or ps = foldr (||) False ps
eg/count.out view
@@ -6,6 +6,7 @@ -- looking through 0 candidates of size 3 -- looking through 0 candidates of size 4 -- looking through 1 candidates of size 5+-- tested 2 candidates count x xs = length (filter (x ==) xs) count :: A -> [A] -> Int@@ -22,6 +23,7 @@ -- looking through 272 candidates of size 9 -- looking through 648 candidates of size 10 -- looking through 1549 candidates of size 11+-- tested 1751 candidates count x [] = 0 count x (y:xs) = (if x == y then 1 else 0) + count x xs
eg/dupos.out view
@@ -18,6 +18,7 @@ -- looking through 644 candidates of size 15 -- looking through 1189 candidates of size 16 -- looking through 2189 candidates of size 17+-- tested 2599 candidates duplicates [] = [] duplicates (x:xs) = if elem x xs && not (elem x (duplicates xs)) then x:duplicates xs else duplicates xs @@ -40,6 +41,7 @@ -- looking through 644 candidates of size 15 -- looking through 1189 candidates of size 16 -- looking through 2189 candidates of size 17+-- tested 2599 candidates duplicates [] = [] duplicates (x:xs) = if elem x xs && not (elem x (duplicates xs)) then x:duplicates xs else duplicates xs @@ -60,6 +62,7 @@ -- looking through 4520 candidates of size 12 -- looking through 10066 candidates of size 13 -- looking through 21492 candidates of size 14+-- tested 19274 candidates positionsFrom x y [] = [] positionsFrom x y (z:xs) = (if y == z then (x :) else id) (positionsFrom (x + 1) y xs)
eg/factorial.out view
@@ -8,6 +8,7 @@ -- looking through 75 candidates of size 5 -- looking through 183 candidates of size 6 -- looking through 577 candidates of size 7+-- tested 343 candidates factorial 0 = 1 factorial x = x * factorial (x - 1) @@ -20,5 +21,6 @@ -- looking through 34 candidates of size 4 -- looking through 75 candidates of size 5 -- looking through 247 candidates of size 6+-- tested 172 candidates factorial x = foldr (*) 1 [1..x]
eg/fib01.out view
@@ -6,6 +6,7 @@ -- looking through 295 candidates of size 3 -- looking through 1968 candidates of size 4 -- looking through 10684 candidates of size 5+-- tested 12982 candidates cannot conjure fib01 :: Int -> Int -> Int -> Int@@ -21,5 +22,6 @@ -- looking through 391 candidates of size 8 -- looking through 840 candidates of size 9 -- looking through 6414 candidates of size 10+-- tested 8002 candidates cannot conjure
eg/fibonacci.out view
@@ -13,6 +13,7 @@ -- looking through 13000 candidates of size 10 -- looking through 33460 candidates of size 11 -- looking through 85901 candidates of size 12+-- tested 56285 candidates fibonacci 0 = 1 fibonacci 1 = 1 fibonacci x = fibonacci (x - 1) + fibonacci (x - 2)
eg/gcd.out view
@@ -7,6 +7,7 @@ -- looking through 60 candidates of size 4 -- looking through 150 candidates of size 5 -- looking through 472 candidates of size 6+-- tested 246 candidates gcd x 0 = x gcd x y = gcd y (x `mod` y)
eg/ints.out view
@@ -4,6 +4,7 @@ -- looking through 0 candidates of size 1 -- looking through 1 candidates of size 2 -- looking through 1 candidates of size 3+-- tested 2 candidates second xs = head (tail xs) third :: [Int] -> Int@@ -13,6 +14,7 @@ -- looking through 1 candidates of size 2 -- looking through 1 candidates of size 3 -- looking through 1 candidates of size 4+-- tested 3 candidates third xs = head (tail (tail xs)) sum :: [Int] -> Int@@ -23,6 +25,7 @@ -- looking through 3 candidates of size 3 -- looking through 13 candidates of size 4 -- looking through 14 candidates of size 5+-- tested 23 candidates sum [] = 0 sum (x:xs) = x + sum xs @@ -34,6 +37,7 @@ -- looking through 3 candidates of size 3 -- looking through 13 candidates of size 4 -- looking through 14 candidates of size 5+-- tested 33 candidates product [] = 1 product (x:xs) = x * product xs @@ -44,6 +48,7 @@ -- looking through 4 candidates of size 2 -- looking through 3 candidates of size 3 -- looking through 16 candidates of size 4+-- tested 10 candidates sum xs = foldr (+) 0 xs product :: [Int] -> Int@@ -53,5 +58,6 @@ -- looking through 4 candidates of size 2 -- looking through 3 candidates of size 3 -- looking through 16 candidates of size 4+-- tested 12 candidates product xs = foldr (*) 1 xs
eg/list.out view
@@ -6,6 +6,7 @@ -- looking through 3 candidates of size 3 -- looking through 11 candidates of size 4 -- looking through 10 candidates of size 5+-- tested 23 candidates length [] = 0 length (x:xs) = length xs + 1 @@ -18,6 +19,7 @@ -- looking through 2 candidates of size 4 -- looking through 5 candidates of size 5 -- looking through 7 candidates of size 6+-- tested 18 candidates reverse [] = [] reverse (x:xs) = reverse xs ++ unit x @@ -30,6 +32,7 @@ -- looking through 44 candidates of size 4 -- looking through 116 candidates of size 5 -- looking through 80 candidates of size 6+-- tested 236 candidates [] ++ xs = xs (x:xs) ++ ys = x:(xs ++ ys) @@ -41,6 +44,7 @@ -- looking through 3 candidates of size 3 -- looking through 13 candidates of size 4 -- looking through 16 candidates of size 5+-- tested 25 candidates length [] = 0 length (x:xs) = length xs + 1 @@ -53,6 +57,7 @@ -- looking through 2 candidates of size 4 -- looking through 5 candidates of size 5 -- looking through 15 candidates of size 6+-- tested 18 candidates reverse [] = [] reverse (x:xs) = reverse xs ++ unit x @@ -63,6 +68,7 @@ -- looking through 8 candidates of size 2 -- looking through 11 candidates of size 3 -- looking through 48 candidates of size 4+-- tested 57 candidates xs ++ ys = foldr (:) ys xs (\/) :: [Int] -> [Int] -> [Int]@@ -74,6 +80,7 @@ -- looking through 44 candidates of size 4 -- looking through 116 candidates of size 5 -- looking through 80 candidates of size 6+-- tested 238 candidates [] \/ xs = xs (x:xs) \/ ys = x:ys \/ xs
eg/pow.out view
@@ -9,6 +9,7 @@ -- looking through 3438 candidates of size 6 -- looking through 21096 candidates of size 7 -- looking through 34780 candidates of size 8+-- tested 27290 candidates pow x 0 = 1 pow x y = x * pow x (y - 1) @@ -21,5 +22,6 @@ -- looking through 378 candidates of size 4 -- looking through 1690 candidates of size 5 -- looking through 4572 candidates of size 6+-- tested 6778 candidates cannot conjure
eg/replicate.out view
@@ -9,6 +9,7 @@ -- looking through 7 candidates of size 6 -- looking through 5 candidates of size 7 -- looking through 16 candidates of size 8+-- tested 20 candidates replicate 0 c = "" replicate x c = c:replicate (x - 1) c @@ -20,6 +21,7 @@ -- looking through 0 candidates of size 3 -- looking through 1 candidates of size 4 -- looking through 1 candidates of size 5+-- tested 3 candidates replicates cs x = concat (transpose (replicate x cs)) replicates :: [Char] -> Int -> [Char]@@ -30,6 +32,7 @@ -- looking through 0 candidates of size 3 -- looking through 0 candidates of size 4 -- looking through 1 candidates of size 5+-- tested 2 candidates replicates cs x = concat (map (replicate x) cs) replicates :: [Char] -> Int -> [Char]@@ -43,6 +46,7 @@ -- looking through 161 candidates of size 6 -- looking through 469 candidates of size 7 -- looking through 1303 candidates of size 8+-- tested 791 candidates replicates "" x = "" replicates (c:cs) x = replicate x c ++ replicates cs x
eg/setelem.out view
@@ -9,6 +9,7 @@ -- looking through 124 candidates of size 6 -- looking through 305 candidates of size 7 -- looking through 999 candidates of size 8+-- tested 826 candidates elem x [] = False elem x (y:xs) = x == y || elem x xs @@ -23,6 +24,7 @@ -- looking through 83 candidates of size 6 -- looking through 245 candidates of size 7 -- looking through 617 candidates of size 8+-- tested 466 candidates set [] = True set (x:xs) = not (elem x xs) && set xs
eg/sort.out view
@@ -6,6 +6,7 @@ -- looking through 7 candidates of size 3 -- looking through 16 candidates of size 4 -- looking through 36 candidates of size 5+-- tested 31 candidates sort [] = [] sort (x:xs) = insert x (sort xs) @@ -16,6 +17,7 @@ -- looking through 1 candidates of size 2 -- looking through 1 candidates of size 3 -- looking through 4 candidates of size 4+-- tested 6 candidates sort xs = foldr insert [] xs qsort :: [Int] -> [Int]@@ -35,6 +37,7 @@ -- looking through 767 candidates of size 12 -- looking through 1600 candidates of size 13 -- looking through 3499 candidates of size 14+-- tested 3668 candidates qsort [] = [] qsort (x:xs) = filter (x >) (qsort xs) ++ (x:filter (x <=) (qsort xs)) @@ -53,5 +56,6 @@ -- looking through 1448 candidates of size 10 -- looking through 12905 candidates of size 11 -- looking through 15208 candidates of size 12+-- tested 34066 candidates cannot conjure
eg/spec.out view
@@ -3,6 +3,7 @@ -- looking through 3 candidates of size 1 -- looking through 4 candidates of size 2 -- looking through 9 candidates of size 3+-- tested 12 candidates square x = x * x square :: Int -> Int@@ -10,6 +11,7 @@ -- looking through 3 candidates of size 1 -- looking through 4 candidates of size 2 -- looking through 9 candidates of size 3+-- tested 12 candidates square x = x * x sum :: [Int] -> Int@@ -19,6 +21,7 @@ -- looking through 3 candidates of size 3 -- looking through 4 candidates of size 4 -- looking through 7 candidates of size 5+-- tested 11 candidates sum [] = 0 sum (x:xs) = x + sum xs @@ -30,6 +33,7 @@ -- looking through 28 candidates of size 4 -- looking through 78 candidates of size 5 -- looking through 172 candidates of size 6+-- tested 196 candidates [] ++ xs = xs (x:xs) ++ ys = x:(xs ++ ys)
eg/subset.out view
@@ -9,6 +9,7 @@ -- looking through 0 candidates of size 6 -- looking through 448 candidates of size 7 -- looking through 784 candidates of size 8+-- tested 1318 candidates subset [] xs = True subset (x:xs) ys = elem x ys && subset xs ys @@ -20,5 +21,6 @@ -- looking through 2 candidates of size 3 -- looking through 6 candidates of size 4 -- looking through 2 candidates of size 5+-- tested 9 candidates subset xs ys = sort xs `isSubsequenceOf` sort ys
eg/tapps.out view
@@ -5,6 +5,7 @@ -- looking through 5 candidates of size 2 -- looking through 6 candidates of size 3 -- looking through 20 candidates of size 4+-- tested 18 candidates third xs = head (tail (tail xs)) product :: [Int] -> Int@@ -15,6 +16,7 @@ -- looking through 6 candidates of size 3 -- looking through 20 candidates of size 4 -- looking through 34 candidates of size 5+-- tested 44 candidates product [] = 1 product (x:xs) = x * product xs @@ -25,5 +27,6 @@ -- looking through 5 candidates of size 2 -- looking through 6 candidates of size 3 -- looking through 23 candidates of size 4+-- tested 20 candidates product xs = foldr (*) 1 xs
eg/tree.out view
@@ -8,6 +8,7 @@ -- looking through 0 candidates of size 5 -- looking through 4 candidates of size 6 -- looking through 16 candidates of size 7+-- tested 9 candidates leftmost Leaf = undefined leftmost (Node t1 x t2) = if nil t1 then x else leftmost t1 @@ -21,6 +22,7 @@ -- looking through 0 candidates of size 5 -- looking through 4 candidates of size 6 -- looking through 16 candidates of size 7+-- tested 18 candidates rightmost Leaf = undefined rightmost (Node t1 x t2) = if nil t2 then x else rightmost t2 @@ -35,6 +37,7 @@ -- looking through 66 candidates of size 6 -- looking through 163 candidates of size 7 -- looking through 311 candidates of size 8+-- tested 428 candidates size Leaf = 0 size (Node t1 x t2) = size t1 + (size t2 + 1) @@ -49,6 +52,7 @@ -- looking through 472 candidates of size 6 -- looking through 1440 candidates of size 7 -- looking through 5781 candidates of size 8+-- tested 4171 candidates height Leaf = -1 height (Node t1 x t2) = max (height t1) (height t2) + 1 @@ -67,6 +71,7 @@ -- looking through 0 candidates of size 10 -- looking through 0 candidates of size 11 -- looking through 184 candidates of size 12+-- tested 107 candidates mem x Leaf = False mem x (Node t1 y t2) = mem x t1 || (x == y || mem x t2) @@ -85,5 +90,6 @@ -- looking through 2204 candidates of size 10 -- looking through 3651 candidates of size 11 -- looking through 8280 candidates of size 12+-- tested 14743 candidates cannot conjure
src/Conjure/Conjurable.hs view
@@ -32,6 +32,7 @@ , conjureIsUnbreakable , conjureReification , conjureReification1+ , conjureDynamicEq , cevaluate , ceval , cevl@@ -48,6 +49,7 @@ import Test.Speculate.Expr import Data.Functor ((<$>)) import Control.Applicative ((<*>))+import Data.Dynamic import Data.Express import Data.Int -- for instances@@ -273,6 +275,13 @@ -- | Computes a function that makes an equation between two expressions. conjureMkEquation :: Conjurable f => f -> Expr -> Expr -> Expr conjureMkEquation f = mkEquation [eq | (_,Just eq,_,_,_,_) <- conjureReification f]++conjureDynamicEq :: Conjurable f => f -> Dynamic+conjureDynamicEq f = case conjureMkEquation f efxs efxs of+ (Value "==" deq :$ _ :$ _) -> deq+ _ -> error "conjureDynamicEq: expected an == but found something else. Bug!"+ where+ efxs = conjureApplication "f" f -- | Given a 'Conjurable' functional value, -- computes a function that checks whether two 'Expr's are equal
src/Conjure/Conjurable/Derive.hs view
@@ -126,11 +126,65 @@ conjureEquality = reifyEquality conjureTiers = reifyTiers |] -- withTheReturnTypeOfs |++| (cxt |=>| inst)- cxt |=>| inst--- TODO: derive conjureCases--- TODO: derive conjureSize--- TODO: derive conjureSubTypes (cf. Extrapolate.subInstances)+ cxt |=>| inst `addFun` deriveSize t `mergeI` deriveSubTypes t `mergeI` deriveCases t+-- TODO: derive conjureCases, e.g.:+-- conjureCases mx = [ value "Nothing" (Nothing -: mx)+-- , value "Just" (Just ->: mx) :$ hole x+-- ] +deriveCases :: Name -> DecsQ+deriveCases t = do+ n <- newName "x"+ (nt,vs) <- normalizeType t+ cs <- typeConstructorsArgNames t+ let lets = [letin n c ns | (c,ns) <- cs]+ let rhs = foldr (\e1 e2 -> [| $e1 : $e2 |]) [|[]|] lets+ [d| instance Conjurable $(return nt) where+ conjureCases $(varP n) = $rhs |]+ where+ letin :: Name -> Name -> [Name] -> ExpQ+ letin x c ns = do+ und <- VarE <$> lookupValN "undefined"+ let lhs = conP c (map varP ns)+ let rhs = return $ foldl AppE (ConE c) [und | _ <- ns]+ let retTypeOf = varE $ mkName $ "-" ++ replicate (length ns) '>' ++ ":"+ let ins = foldl (\e1 e2 -> [| $e1 :$ $e2 |])+ [| value $(stringE $ nameBase c) ($retTypeOf $(conE c) $(varE x)) |]+ [ [| hole $(varE n) |] | n <- ns ]+ [| let $lhs = $rhs `asTypeOf` $(varE x) in $ins |]++deriveSubTypes :: Name -> DecsQ+deriveSubTypes t = do+ n <- newName "x"+ (nt,vs) <- normalizeType t+ cs <- typeConstructorsArgNames t+ let lets = [letin n c ns | (c,ns) <- cs, not (null ns)]+ let rhs = foldr0 (\e1 e2 -> [| $e1 . $e2 |]) [|id|] lets+ [d| instance Conjurable $(return nt) where+ conjureSubTypes $(varP n) = $rhs |]+ where+ letin :: Name -> Name -> [Name] -> ExpQ+ letin x c ns = do+ und <- VarE <$> lookupValN "undefined"+ let lhs = conP c (map varP ns)+ let rhs = return $ foldl AppE (ConE c) [und | _ <- ns]+ let bot = foldl1 (\e1 e2 -> [| $e1 . $e2 |])+ [ [| conjureType $(varE n) |] | n <- ns ]+ [| let $lhs = $rhs `asTypeOf` $(varE x) in $bot |]++deriveSize :: Name -> DecsQ+deriveSize t = ((:[]) . FunD (mkName "conjureSize")) <$> deriveSizeClauses t++deriveSizeClauses :: Name -> Q [Clause]+deriveSizeClauses t = mapM (uncurry mkClause) =<< typeConstructors t+ where+ mkClause :: Name -> [Type] -> Q Clause+ mkClause n as = clause pat body []+ where+ ns = take (length as) $ map mkName (variableNamesFromTemplate "x")+ pat = [conP n [varP n | n <- ns]]+ body = normalB $ foldl (\e n -> [| $e + conjureSize $(varE n) |]) [| 1 |] ns+ -- Not only really derive Conjurable instances, -- but cascade through argument types. reallyDeriveConjurableCascading :: Name -> DecsQ@@ -164,4 +218,15 @@ bind = id -- unbound variables are automatically bound #else bind = toBoundedQ+#endif++addFun :: DecsQ -> DecsQ -> DecsQ+qds1 `addFun` qds2 = do ds1 <- qds1+ ds2 <- qds2+ return $ ds1 `m` ds2+ where+#if __GLASGOW_HASKELL__ < 800+ [InstanceD c ts ds1] `m` ds2 = [InstanceD c ts (ds1 ++ ds2)]+#else+ [InstanceD o c ts ds1] `m` ds2 = [InstanceD o c ts (ds1 ++ ds2)] #endif
src/Conjure/Engine.hs view
@@ -44,12 +44,14 @@ import Data.Express.Fixtures hiding ((-==-)) import qualified Data.Express.Triexpr as T +import Data.Dynamic (fromDyn, dynApp)+ import Test.LeanCheck import Test.LeanCheck.Tiers import Test.LeanCheck.Error (errorToTrue, errorToFalse, errorToNothing) import Test.Speculate.Reason (Thy, rules, equations, invalid, canReduceTo, printThy, closureLimit, doubleCheck)-import Test.Speculate.Engine (theoryFromAtoms, groundBinds, boolTy)+import Test.Speculate.Engine (theoryFromAtoms, grounds, groundBinds, boolTy) import Conjure.Expr import Conjure.Conjurable@@ -162,6 +164,7 @@ , requireDescent :: Bool -- ^ require recursive calls to deconstruct arguments , usePatterns :: Bool -- ^ use pattern matching to create (recursive) candidates , showTheory :: Bool -- ^ show theory discovered by Speculate used in pruning+ , uniqueCandidates :: Bool -- ^ unique-modulo-testing candidates } @@ -175,6 +178,7 @@ -- * search for defined applications for up to 100000 combinations -- * require recursive calls to deconstruct arguments -- * don't show the theory used in pruning+-- * do not make candidates unique module testing args :: Args args = Args { maxTests = 360@@ -186,6 +190,7 @@ , requireDescent = True , usePatterns = True , showTheory = False+ , uniqueCandidates = False } @@ -216,17 +221,19 @@ putStrLn $ "-- reasoning produced " ++ show (length (invalid thy)) ++ " incorrect properties," ++ " please re-run with more tests for faster results"- pr 1 rs+ pr 1 0 rs where- pr n [] = putStrLn $ "cannot conjure\n"- pr n ((is,cs):rs) = do- putStrLn $ "-- looking through "- ++ show (length cs)- ++ " candidates of size " ++ show n+ pr n t [] = do putStrLn $ "-- tested " ++ show t ++ " candidates"+ putStrLn $ "cannot conjure\n"+ pr n t ((is,cs):rs) = do+ let nc = length cs+ putStrLn $ "-- looking through " ++ show nc ++ " candidates of size " ++ show n -- when (n<=12) $ putStrLn $ unlines $ map showDefn cs case is of- [] -> pr (n+1) rs- (i:_) -> putStrLn $ showDefn i+ [] -> pr (n+1) (t+nc) rs+ (i:_) -> do let nc' = fromMaybe nc (findIndex (i==) cs)+ putStrLn $ "-- tested " ++ show (t+nc'+1) ++ " candidates"+ putStrLn $ showDefn i rs = zip iss css (iss, css, ts, thy) = conjpure0With args nm f p es nRules = length (rules thy)@@ -274,7 +281,8 @@ implements fx = defnApparentlyTerminates fx && requal fx ffxx vffxx && errorToFalse (p (cevl maxEvalRecursions fx))- candidatesT = take maxSize candidatesTT+ candidatesT = (if uniqueCandidates then nubCandidates args nm f else id)+ $ take maxSize candidatesTT (candidatesTT, thy) = candidateDefns args nm f es ffxx = conjureApplication nm f vffxx = conjureVarApplication nm f@@ -311,11 +319,25 @@ -- | Return apparently unique candidate definitions. candidateDefns :: Conjurable f => Args -> String -> f -> [Prim] -> ([[Defn]], Thy)-candidateDefns args = cds args+candidateDefns args = candidateDefns' args where- cds = if usePatterns args- then candidateDefnsC- else candidateDefns1+ candidateDefns' = if usePatterns args+ then candidateDefnsC+ else candidateDefns1+++nubCandidates :: Conjurable f => Args -> String -> f -> [[Defn]] -> [[Defn]]+nubCandidates Args{..} nm f = discardLaterT (===)+ where+ err = error "nubCandidates: unexpected evaluation error."+ eq = conjureDynamicEq f+ d1 === d2 = all are $ take maxTests $ grounds (conjureTiersFor f) (conjureVarApplication nm f)+ where+ are :: Expr -> Bool+ are e = errorToFalse -- silences errors, ok since this is for optional measuring of optimal pruning+ $ (`fromDyn` err)+ $ eq `dynApp` fromMaybe err (toDynamicWithDefn (conjureExpress f) maxEvalRecursions d1 e)+ `dynApp` fromMaybe err (toDynamicWithDefn (conjureExpress f) maxEvalRecursions d2 e) -- | Return apparently unique candidate definitions
src/Conjure/Utils.hs view
@@ -31,6 +31,7 @@ , allEqual , choices , choicesThat+ , foldr0 ) where @@ -126,3 +127,8 @@ -- | Lists choices of values that follow a property. choicesThat :: (a -> [a] -> Bool) -> [a] -> [(a,[a])] choicesThat (?) = filter (uncurry (?)) . choices++-- | A variation of foldr that only uses "zero" when the list is empty+foldr0 :: (a -> a -> a) -> a -> [a] -> a+foldr0 f z xs | null xs = z+ | otherwise = foldr1 f xs
stack.yaml view
@@ -3,7 +3,7 @@ # Copyright (C) 2021 Rudy Matela # Distributed under the 3-Clause BSD licence (see the file LICENSE). -resolver: lts-17.9 # or ghc-8.10.4+resolver: lts-18.14 # or ghc-8.10.7 packages: - .
test/conjurable.hs view
@@ -4,6 +4,7 @@ {-# Language DeriveDataTypeable, StandaloneDeriving #-} -- for GHC < 7.10 import Test+import Data.Dynamic -- An Unit type that is not an Eq instance data Unit = Unit deriving Show@@ -193,6 +194,76 @@ ] ] + , concat (conjurePats [zero, one] "foo" (undefined :: [Int] -> Int -> Int))+ == [ [ ffoo xxs xx+ ]+ , [ ffoo xxs zero+ , ffoo xxs xx+ ]+ , [ ffoo nil xx+ , ffoo (xx -:- xxs) yy+ ]+ , [ ffoo xxs one+ , ffoo xxs xx+ ]+ , [ ffoo nil zero+ , ffoo nil xx+ , ffoo (xx -:- xxs) zero+ , ffoo (xx -:- xxs) yy+ ]+ , [ ffoo xxs zero+ , ffoo xxs one+ , ffoo xxs xx+ ]+ , [ ffoo nil one+ , ffoo nil xx+ , ffoo (xx -:- xxs) one+ , ffoo (xx -:- xxs) yy+ ]+ , [ ffoo nil zero+ , ffoo nil one+ , ffoo nil xx+ , ffoo (xx -:- xxs) zero+ , ffoo (xx -:- xxs) one+ , ffoo (xx -:- xxs) yy+ ]+ ]++ , concat (conjurePats [zero, one] "foo" (undefined :: Int -> [Int] -> Int))+ == [ [ ffoo xx xxs+ ]+ , [ ffoo xx nil+ , ffoo xx (yy -:- xxs)+ ]+ , [ ffoo zero xxs+ , ffoo xx xxs+ ]+ , [ ffoo zero nil+ , ffoo zero (xx -:- xxs)+ , ffoo xx nil+ , ffoo xx (yy -:- xxs)+ ]+ , [ ffoo one xxs+ , ffoo xx xxs+ ]+ , [ ffoo one nil+ , ffoo one (xx -:- xxs)+ , ffoo xx nil+ , ffoo xx (yy -:- xxs)+ ]+ , [ ffoo zero xxs+ , ffoo one xxs+ , ffoo xx xxs+ ]+ , [ ffoo zero nil+ , ffoo zero (xx -:- xxs)+ , ffoo one nil+ , ffoo one (xx -:- xxs)+ , ffoo xx nil+ , ffoo xx (yy -:- xxs)+ ]+ ]+ , conjurePats [] "foo" (undefined :: [Int] -> [Char] -> Int) == [ [ [ ffoo xxs ccs ]@@ -248,6 +319,11 @@ ] , candidateDeconstructionsFrom (div' xx xx) == [] , candidateDeconstructionsFrom ((xx -+- xx) -+- yy) == [(xx -+- xx) -+- i_]++ , fromDynamic (conjureDynamicEq ((+) :: Int -> Int -> Int) `dynApp` toDyn (1::Int) `dynApp` toDyn (2::Int))+ == Just False+ , fromDynamic (conjureDynamicEq ((+) :: Int -> Int -> Int) `dynApp` toDyn (1::Int) `dynApp` toDyn (1::Int))+ == Just True ] isDecon :: Expr -> Bool@@ -259,9 +335,15 @@ ffE = var "f" (undefined :: [Int] -> Int) ffoo :: Expr -> Expr -> Expr-ffoo e1 e2 = fooE :$ e1 :$ e2+ffoo ex ey = headOr err . mapMaybe ($$ ey) . mapMaybe ($$ ex)+ $ [ var "foo" (undefined :: [Int] -> [Char] -> Int)+ , var "foo" (undefined :: Int -> [Int] -> Int)+ , var "foo" (undefined :: [Int] -> Int -> Int)+ ] where- fooE = var "foo" (undefined :: [Int] -> [Char] -> Int)+ err = error $ "ffoo: cannot apply `foo :: * -> * -> *` to `"+ ++ show ex ++ "' and `" ++ show ey ++ "'. Unhandled types?"+ -- Equality but obtained through conjurable (<==>) :: Conjurable a => a -> a -> Bool
test/derive.hs view
@@ -3,6 +3,9 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DeriveDataTypeable #-} +-- uncomment to debug derivation:+-- {-# OPTIONS_GHC -ddump-splices #-}+ import Test hiding ((-:), (->:)) -- -: and ->: should be generated by deriveConjurable @@ -74,6 +77,78 @@ , conjurableOK (undefined :: Bush Int) , conjurableOK (undefined :: Tree Int) --, conjurableOK (undefined :: RN) -- TODO: FIX: infinite loop somewhere...++ , conjureSize Ae == 1+ , conjureSize Bee == 1+ , conjureSize Cee == 1+ , conjureSize Zero == 1+ , conjureSize (Succ Zero) == 2+ , conjureSize (Succ (Succ Zero)) == 3+ , conjureSize (Nil :: List Int) == 1+ , conjureSize (10 :- (20 :- Nil) :: List Int) == 33++ , conjureCases choice+ == [ val Ae+ , val Bee+ , val Cee+ ]++ , conjureCases peano+ == [ val Zero+ , value "Succ" Succ :$ hole (undefined :: Peano)+ ]++ , conjureCases (lst int)+ == [ value ":-" ((:-) ->>: lst int) :$ hole int :$ hole (lst int)+ , val (Nil :: List Int)+ ]++ , conjureCases (bush int)+ == [ value ":-:" ((:-:) ->>: bush int) :$ hole (bush int) :$ hole (bush int)+ , value "Leaf" (Leaf ->: bush int) :$ hole int+ ]++ , conjureCases (tree int)+ == [ value "Node" (Node ->>>: tree int) :$ hole (tree int) :$ hole int :$ hole (tree int)+ , val (Null :: Tree Int)+ ]++ , conjureCases nested+ == [ value "Nested" Nested :$ hole n0 :$ hole (n1 int) :$ hole (n2 int int)+ ]++ , conjureHoles (undefined :: Choice) == [ hole (undefined :: Choice)+ , hole (undefined :: Bool)+ ]+ , conjureHoles (undefined :: Peano) == [ hole (undefined :: Peano)+ , hole (undefined :: Bool)+ ]+ , conjureHoles (undefined :: List Int) == [ hole (undefined :: Int)+ , hole (undefined :: List Int)+ , hole (undefined :: Bool)+ ]+ , conjureHoles (undefined :: Nested) == [ hole (undefined :: N0)+ , hole (undefined :: N1 Int)+ , hole (undefined :: Int)+ , hole (undefined :: N2 Int Int)+ , hole (undefined :: Nested)+ , hole (undefined :: Bool)+ ]+ , conjureHoles (undefined :: RN) == [ hole (undefined :: RN0)+ , hole (undefined :: RN1 Int)+ , hole (undefined :: Int)+ , hole (undefined :: RN2 Int RN)+ , hole (undefined :: RN)+ , hole (undefined :: Bool)+ ]+ , conjureHoles (undefined :: Mutual) == [ hole (undefined :: CoMutual)+ , hole (undefined :: Mutual)+ , hole (undefined :: Bool)+ ]+ , conjureHoles (undefined :: CoMutual) == [ hole (undefined :: Mutual)+ , hole (undefined :: CoMutual)+ , hole (undefined :: Bool)+ ] ] @@ -89,3 +164,32 @@ (-==-) = evl (fromJust $ conjureEquality x) -:> x tiers' = mapT evl (fromJust $ conjureTiers x) -: [[x]] expr' = (conjureExpress x . val) -:> x+++-- proxies --+choice :: Choice+choice = undefined++peano :: Peano+peano = undefined++lst :: a -> List a+lst _ = undefined++bush :: a -> Bush a+bush _ = undefined++tree :: a -> Tree a+tree _ = undefined++nested :: Nested+nested = undefined++n0 :: N0+n0 = undefined++n1 :: a -> N1 a+n1 _ = undefined++n2 :: a -> b -> N2 a b+n2 _ _ = undefined