packages feed

code-conjure 0.4.4 → 0.5.0

raw patch · 51 files changed

+1234/−889 lines, 51 filesdep ~expressdep ~leancheckdep ~speculatePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: express, leancheck, speculate

API changes (from Hackage documentation)

- Conjure: (-=) :: a -> b -> (a, b)
- Conjure: [forceTests] :: Args -> [[Expr]]
- Conjure: conjure1 :: (Eq a, Eq b, Show a, Express a, Conjurable a, Conjurable b) => String -> Spec1 a b -> [Prim] -> IO ()
- Conjure: conjure1With :: (Eq a, Eq b, Show a, Express a, Conjurable a, Conjurable b) => Args -> String -> Spec1 a b -> [Prim] -> IO ()
- Conjure: conjure2 :: (Conjurable a, Eq a, Show a, Express a, Conjurable b, Eq b, Show b, Express b, Conjurable c, Eq c) => String -> Spec2 a b c -> [Prim] -> IO ()
- Conjure: conjure2With :: (Conjurable a, Eq a, Show a, Express a, Conjurable b, Eq b, Show b, Express b, Conjurable c, Eq c) => Args -> String -> Spec2 a b c -> [Prim] -> IO ()
- Conjure: conjure3 :: (Conjurable a, Eq a, Show a, Express a, Conjurable b, Eq b, Show b, Express b, Conjurable c, Eq c, Show c, Express c, Conjurable d, Eq d) => String -> Spec3 a b c d -> [Prim] -> IO ()
- Conjure: conjure3With :: (Conjurable a, Eq a, Show a, Express a, Conjurable b, Eq b, Show b, Express b, Conjurable c, Eq c, Show c, Express c, Conjurable d, Eq d) => Args -> String -> Spec3 a b c d -> [Prim] -> IO ()
- Conjure: type Spec1 a b = [(a, b)]
- Conjure: type Spec2 a b c = [((a, b), c)]
- Conjure: type Spec3 a b c d = [((a, b, c), d)]
- Conjure.Engine: [forceTests] :: Args -> [[Expr]]
- Conjure.Engine: deconstructions :: (a -> Bool) -> (a -> a) -> a -> [a]
- Conjure.Expr: applicationOld :: Expr -> [Expr] -> Maybe Expr
- Conjure.Expr: isDeconstructionE :: [Expr] -> Expr -> Expr -> Bool
- Conjure.Expr: lhs :: Expr -> Expr
- Conjure.Expr: primitiveApplications :: [Expr] -> [[Expr]]
- Conjure.Expr: primitiveHoles :: [Expr] -> [Expr]
- Conjure.Expr: rhs :: Expr -> Expr
- Conjure.Expr: showEq :: Expr -> String
- Conjure.Spec: (-=) :: a -> b -> (a, b)
- Conjure.Spec: conjure1 :: (Eq a, Eq b, Show a, Express a, Conjurable a, Conjurable b) => String -> Spec1 a b -> [Prim] -> IO ()
- Conjure.Spec: conjure1With :: (Eq a, Eq b, Show a, Express a, Conjurable a, Conjurable b) => Args -> String -> Spec1 a b -> [Prim] -> IO ()
- Conjure.Spec: conjure2 :: (Conjurable a, Eq a, Show a, Express a, Conjurable b, Eq b, Show b, Express b, Conjurable c, Eq c) => String -> Spec2 a b c -> [Prim] -> IO ()
- Conjure.Spec: conjure2With :: (Conjurable a, Eq a, Show a, Express a, Conjurable b, Eq b, Show b, Express b, Conjurable c, Eq c) => Args -> String -> Spec2 a b c -> [Prim] -> IO ()
- Conjure.Spec: conjure3 :: (Conjurable a, Eq a, Show a, Express a, Conjurable b, Eq b, Show b, Express b, Conjurable c, Eq c, Show c, Express c, Conjurable d, Eq d) => String -> Spec3 a b c d -> [Prim] -> IO ()
- Conjure.Spec: conjure3With :: (Conjurable a, Eq a, Show a, Express a, Conjurable b, Eq b, Show b, Express b, Conjurable c, Eq c, Show c, Express c, Conjurable d, Eq d) => Args -> String -> Spec3 a b c d -> [Prim] -> IO ()
- Conjure.Spec: type Spec1 a b = [(a, b)]
- Conjure.Spec: type Spec2 a b c = [((a, b), c)]
- Conjure.Spec: type Spec3 a b c d = [((a, b, c), d)]
- Conjure.Utils: deconstructions :: (a -> Bool) -> (a -> a) -> a -> [a]
- Conjure.Utils: filterAnd :: (a -> Bool) -> [a] -> ([a], Bool)
- Conjure.Utils: isDeconstruction :: [a] -> (a -> Bool) -> (a -> a) -> Bool
- Conjure.Utils: iterateUntil :: (a -> a -> Bool) -> (a -> a) -> a -> a
- Conjure.Utils: takeNextUntil :: (a -> a -> Bool) -> [a] -> [a]
- Conjure.Utils: takeNextWhile :: (a -> a -> Bool) -> [a] -> [a]
- Conjure.Utils: takeUntil :: (a -> Bool) -> [a] -> [a]
+ Conjure: conjureFromSpec :: Conjurable f => String -> (f -> Bool) -> [Prim] -> IO ()
+ Conjure: conjureFromSpecWith :: Conjurable f => Args -> String -> (f -> Bool) -> [Prim] -> IO ()
+ Conjure: deriveConjurable :: Name -> DecsQ
+ Conjure: deriveConjurableCascading :: Name -> DecsQ
+ Conjure: deriveConjurableIfNeeded :: Name -> DecsQ
+ Conjure.Conjurable.Derive: deriveConjurable :: Name -> DecsQ
+ Conjure.Conjurable.Derive: deriveConjurableCascading :: Name -> DecsQ
+ Conjure.Conjurable.Derive: deriveConjurableIfNeeded :: Name -> DecsQ
+ Conjure.Engine: conjpure0 :: Conjurable f => String -> f -> (f -> Bool) -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy)
+ Conjure.Engine: conjpure0With :: Conjurable f => Args -> String -> f -> (f -> Bool) -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy)
+ Conjure.Engine: conjpureFromSpec :: Conjurable f => String -> (f -> Bool) -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy)
+ Conjure.Engine: conjpureFromSpecWith :: Conjurable f => Args -> String -> (f -> Bool) -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy)
+ Conjure.Engine: conjure0 :: Conjurable f => String -> f -> (f -> Bool) -> [Prim] -> IO ()
+ Conjure.Engine: conjure0With :: Conjurable f => Args -> String -> f -> (f -> Bool) -> [Prim] -> IO ()
+ Conjure.Engine: conjureFromSpec :: Conjurable f => String -> (f -> Bool) -> [Prim] -> IO ()
+ Conjure.Engine: conjureFromSpecWith :: Conjurable f => Args -> String -> (f -> Bool) -> [Prim] -> IO ()
- Conjure: Args :: Int -> Int -> Int -> Int -> Int -> Int -> Bool -> Bool -> Bool -> [[Expr]] -> Args
+ Conjure: Args :: Int -> Int -> Int -> Int -> Int -> Int -> Bool -> Bool -> Bool -> Args
- Conjure.Engine: Args :: Int -> Int -> Int -> Int -> Int -> Int -> Bool -> Bool -> Bool -> [[Expr]] -> Args
+ Conjure.Engine: Args :: Int -> Int -> Int -> Int -> Int -> Int -> Bool -> Bool -> Bool -> Args

Files

.gitignore view
@@ -65,3 +65,4 @@ test/utils test/cases test/defn+test/derive
Makefile view
@@ -2,7 +2,11 @@ GHCFLAGS = -O2 \   $(shell grep -q "Arch Linux" /etc/lsb-release && echo -dynamic) HADDOCKFLAGS = \+  -i $(shell find ~/.cabal -name express.haddock | tail -1) \+  -i $(shell find ~/.cabal -name speculate.haddock | tail -1) \+  -i $(shell find /usr/share/doc/ghc/html/libraries -name template-haskell.haddock | tail -1) \   $(shell grep -q "Arch Linux" /etc/lsb-release && echo --optghc=-dynamic)+HADDOCK_FILTER = grep -v "^Warning: Couldn't find .haddock for export [A-Z]$$" INSTALL_DEPS = leancheck express speculate  EG = \@@ -113,5 +117,15 @@ avgs: 	runhaskell bench/avgs.hs <bench/runtime/$$HOSTNAME/p12.runtimes 	runhaskell bench/avgs.hs <bench/runtime/$$HOSTNAME/p30.runtimes++gps-each: bench/gps+	for i in {1..29}; do ./bench/time ./bench/gps $$i; done++terpret-each: bench/terpret+	for i in {1..8}; do ./bench/time ./bench/terpret $$i; done++gps2-each: bench/gps2+	for i in {1..25}; do ./bench/time ./bench/gps2 $$i; done+  include mk/haskell.mk
README.md view
@@ -8,11 +8,7 @@  ![Conjure logo][conjure-logo] -Conjure is a tool that produces Haskell functions out of partial definitions.--This is currently an experimental tool in its early stages,-don't expect much from its current version.-It is just a piece of curiosity in its current state.+Conjure is a tool that synthesizes Haskell functions out of partial definitions.   Installing@@ -34,21 +30,27 @@ -- not to be confused with [Conjure the BitTorrent client].  -Conjuring functions--------------------+Synthesizing functions+---------------------- -You first need to import the library with:+To use Conjure, import the library with:  	import Conjure -Then, given+Then, declare a partial definition of a function to be synthesized.+For example,+here is a partial implementation of a function that squares a number:  	square :: Int -> Int 	square 0  =  0 	square 1  =  1 	square 2  =  4 -and+Next, declare a list of primitives that seem like interesting pieces+in the final fully-defined implementation.+For example,+here is a list of primitives including+addition, multiplication and their neutral elements:  	primitives :: [Prim] 	primitives  =  [ pr (0::Int)@@ -57,12 +59,10 @@ 	               , prim "*" ((*) :: Int -> Int -> Int) 	               ] -running+Finally, call the [`conjure`] function,+passing the function name, the partial definition and the list of primitives:  	> conjure "square" square primitives--yields- 	square :: Int -> Int 	-- testing 3 combinations of argument values 	-- pruning with 14/25 rules@@ -71,23 +71,27 @@ 	-- looking through 9 candidates of size 3 	square x  =  x * x -in less than a second.+Conjure is able to synthesize the above implementation in less than a second. -See the `eg/arith.hs` example.+For more information, see the `eg/arith.hs` example and+the Haddock documentation for the [`conjure`] and [`conjureWith`] functions.  -Conjuring recursive functions------------------------------+Synthesizing recursive functions+-------------------------------- -Given+Conjure supports synthetization of recursive functions. +Take for example the following partial implementation of a function+that computes the factorial of a number:+ 	factorial :: Int -> Int 	factorial 1  =  1 	factorial 2  =  2 	factorial 3  =  6 	factorial 4  =  24 -and+Here is a list of primitives:  	primitives :: [Prim] 	primitives  =  [ pr (0::Int)@@ -97,12 +101,10 @@ 	               , prim "-" ((-) :: Int -> Int -> Int) 	               ] -running+And here is what Conjure produces+with the above partial definition and list of primitives:  	> conjure "factorial" factorial primitives--yields- 	factorial :: Int -> Int 	-- testing 4 combinations of argument values 	-- pruning with 27/65 rules@@ -116,25 +118,185 @@ 	factorial 0  =  1 	factorial x  =  x * factorial (x - 1) -in less than a second.+The above synthetization takes less than a second. -It is also possible to generate+It is also possible to generate a folding implementation+like the following:  	factorial x  =  foldr (*) 1 [1..x] -by including `enumFromTo` and `foldr` in the background.+by including [`enumFromTo`] and [`foldr`] in the background. -See the `eg/factorial.hs` example.+For more information, see the `eg/factorial.hs` example and+the Haddock documentation for the [`conjure`] and [`conjureWith`] functions.  +Synthesizing from specifications (for advanced users)+-----------------------------------------------------++Conjure also supports synthesizing from a functional specification+with the functions [`conjureFromSpec`] and [`conjureFromSpecWith`]+as, in some cases,+a partial definition may not be appropriate+for one of two reasons:++1. Conjure may fail to "hit" the appropriate data points;+2. specifying argument-result bindings may not be easy.++Take for example a function `duplicates :: Eq a => [a] -> [a]`+that should return the duplicate elements in a list without repetitions.++Let's start with the primitives:++	primitives :: [Prim]+	primitives  =  [ pr ([] :: [Int])+	               , prim "not" not+	               , prim "&&" (&&)+	               , prim ":" ((:) :: Int -> [Int] -> [Int])+	               , prim "elem" (elem :: Int -> [Int] -> Bool)+	               , prif (undefined :: [Int])+	               ]++Now here's a first attempt at a partial definition:++	duplicates' :: [Int] -> [Int]+	duplicates' []  =  []+	duplicates' [1,2,3,4,5]  =  []+	duplicates' [1,2,2,3,4]  =  [2]+	duplicates' [1,2,3,3,3]  =  [3]+	duplicates' [1,2,2,3,3]  =  [2,3]++Here is what [`conjureWith`] prints:++	> conjureWith args{maxSize=18} "duplicates" duplicates primitives+	duplicates :: [Int] -> [Int]+	-- testing 1 combinations of argument values+	-- pruning with 21/26 rules+	-- looking through 2 candidates of size 1+	duplicates xs  =  xs++The generated function clearly does not follow our specification.+But if we look at the reported number of tests,+we see that only _one_ of the argument-result bindings+of our partial definition was used.+Conjure failed to hit any of the argument values with five elements.+(Since Conjure uses enumeration to test functions these values have to be kept "small").++Here is a second attempt:++	duplicates :: [Int] -> [Int]+	duplicates [0,0]  =  [0]+	duplicates [0,1]  =  []+	duplicates [1,0,1]  =  [1]++Here is what [`conjureWith`] now prints:++	> conjureWith args{maxSize=18} "duplicates" duplicates primitives+	duplicates :: [Int] -> [Int]+	-- testing 3 combinations of argument values+	-- pruning with 21/26 rules+	-- ...+	-- looking through 16 candidates of size 9+	duplicates []  =  []+	duplicates (x:xs)  =  if elem x xs then [x] else []++The `duplicates` function that Conjure generated is still not correct.+Nevertheless, it does follow our partial definition.  We have to refine it.+Here is a third attempt with more argument-result bindings:++	duplicates :: [Int] -> [Int]+	duplicates [0,0]  =  [0]+	duplicates [0,1]  =  []+	duplicates [1,0,1]  =  [1]+	duplicates [0,1,0,1]  =  [0,1]++Here is what Conjure prints:++	duplicates []  =  []+	duplicates (x:xs)  =  if elem x xs then x:duplicates xs else []++This implementation follows our partial definition, but may return duplicate duplicates,+see:++	duplicates [1,0,1,0,1]  =  [1,0,1]++Here is a fourth and final refinement:++	duplicates :: [Int] -> [Int]+	duplicates [0,0]  =  [0]+	duplicates [0,1]  =  []+	duplicates [1,0,1]  =  [1]+	duplicates [0,1,0,1]  =  [0,1]+	duplicates [1,0,1,0,1]  =  [0,1]+	duplicates [0,1,2,1]  =  [1]++Now Conjure prints a correct implementation:++	> conjureWith args{maxSize=18} "duplicates" duplicates primitives+	duplicates :: [Int] -> [Int]+	-- testing 6 combinations of argument values+	-- ...+	-- looking through 2189 candidates of size 17+	duplicates []  =  []+	duplicates (x:xs)  =  if elem x xs && not (elem x (duplicates xs)) then x:duplicates xs else duplicates xs+	(in 1.5s)++In this case,+specifying the function with specific argument-result bindings+is perhaps not the best approach.+It took us four refinements of the partial definition to get a result.+Specifying test properties perhaps better describes what we want.+Again, we would like `duplicates` to return all duplicate elements+without repetitions.+This can be encoded in a function using [`holds`] from [LeanCheck]:++	import Test.LeanCheck (holds)++	duplicatesSpec :: ([Int] -> [Int]) -> Bool+	duplicatesSpec duplicates  =  and+	  [ holds 360 $ \x xs -> (count (x ==) xs > 1) == elem x (duplicates xs)+	  , holds 360 $ \x xs -> count (x ==) (duplicates xs) <= 1+	  ]  where  count p  =  length . filter p++This function takes as argument a candidate implementation of `duplicates`+and returns whether it is valid.+The first property states that all duplicates must be listed.+The second property states that duplicates themselves must not repeat.++Now, we can use the function [`conjureFromSpecWith`] to generate the same duplicates function+passing our `duplicatesSpec` as argument:++	> conjureFromSpecWith args{maxSize=18} "duplicates" duplicatesSpec primitives+	duplicates :: [Int] -> [Int]+	duplicates []  =  []+	duplicates (x:xs)  =  if elem x xs && not (elem x (duplicates xs)) then x:duplicates xs else duplicates xs+	(in 1.5s)++For more information see the `eg/dupos.hs` example and+the Haddock documentation for the [`conjureFromSpec`] and [`conjureFromSpecWith`] functions.++The functions [`conjureFromSpec`] and [`conjureFromSpecWith`] also accept specifications+that bind specific arguments to results.+Just use `==` and `&&` accordingly:++	duplicatesSpec :: ([Int] -> [Int]) -> Bool+	duplicatesSpec duplicates  =  duplicates [0,0] == [0]+	                           && duplicates [0,1]  ==  []+	                           && duplicates [1,0,1]  ==  [1]+	                           && duplicates [0,1,0,1]  ==  [0,1]+	                           && duplicates [1,0,1,0,1]  ==  [0,1]+	                           && duplicates [0,1,2,1]  ==  [1]++With this, there is no way for Conjure to miss argument-result bindings.++ Related work ------------  [MagicHaskeller] (2007) is another tool that is able to generate Haskell code automatically. It supports recursion through-catamorphisms, paramorphisms and the [fix] function.-It is more mature than Conjure and is several orders of magnitude faster.+catamorphisms, paramorphisms and the [`fix`] function.  [Barliman] for Lisp is another tool that does program synthesis. @@ -148,14 +310,25 @@ For a detailed documentation of each function, see [Conjure's Haddock documentation]. +The `eg` folder in the source distribution+contains more than 60 examples of use. + Conjure, Copyright 2021  Rudy Matela, distribued under the 3-clause BSD license.   [Conjure's Haddock documentation]: https://hackage.haskell.org/package/code-conjure/docs/Conjure.html-[fix]: https://hackage.haskell.org/package/base/docs/Data-Function.html#v:fix+[`conjure`]:             https://hackage.haskell.org/package/code-conjure/docs/Conjure.html#v:conjure+[`conjureWith`]:         https://hackage.haskell.org/package/code-conjure/docs/Conjure.html#v:conjureWith+[`conjureFromSpec`]:     https://hackage.haskell.org/package/code-conjure/docs/Conjure.html#v:conjureFromSpec+[`conjureFromSpecWith`]: https://hackage.haskell.org/package/code-conjure/docs/Conjure.html#v:conjureFromSpecWith +[`foldr`]:               https://hackage.haskell.org/package/base/docs/Prelude.html#v:foldr+[`enumFromTo`]:          https://hackage.haskell.org/package/base/docs/Prelude.html#v:enumFromTo+[`fix`]:                 https://hackage.haskell.org/package/base/docs/Data-Function.html#v:fix+[`holds`]:               https://hackage.haskell.org/package/leancheck/docs/Test-LeanCheck.html#v:holds+ [symbol `>`]: https://www.haskell.org/haddock/doc/html/ch03s08.html#idm140354810780208 [Template Haskell]: https://wiki.haskell.org/Template_Haskell @@ -167,6 +340,7 @@ [Cabal]:   https://www.haskell.org/cabal [Haskell]: https://www.haskell.org/ [leancheck]:      https://hackage.haskell.org/package/leancheck+[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
TODO.md view
@@ -3,6 +3,10 @@  A non-exhaustive list of things TO DO for Conjure. +* derive `conjureCases`, `conjureSize` and `conjureSubTypes`;++* implement `deriveConjurable` using TH (cf. `deriveExpress` and `deriveGeneralizable`);+ * consider not breaking in some cases (increased crossproduct of patterns)  * reduce the number of `deconstructions` considered:
bench/gps.hs view
@@ -587,9 +587,9 @@   -- GPS Benchmark #20 -- Pig Latin ---gps20p :: String -> String-gps20p "hello world"  =  "ellohay orldway"-gps20p "a string"  =  "aay tringsay"+gps20s :: (String -> String) -> Bool+gps20s pig  =  pig "hello world" == "ellohay orldway"+            && pig "a string"    == "aay tringsay"  gps20g :: String -> String gps20g  =  pig@@ -602,11 +602,11 @@                 then (c:cs) ++ "ay"                 else cs ++ (c:"ay") -pig1' :: String -> String-pig1' "hello"   =  "ellohay"-pig1' "world"   =  "orldway"-pig1' "string"  =  "tringsay"-pig1' "east"    =  "eastay"+pig1Spec :: (String -> String) -> Bool+pig1Spec pig1  =  pig1 "hello" == "ellohay"+               && pig1 "world"  == "orldway"+               && pig1 "string" == "tringsay"+               && pig1 "east"   == "eastay"  isVowel :: Char -> Bool isVowel 'a'  =  True@@ -644,12 +644,7 @@     , pr False     ] -  let force  =  [ [val "hello"]-                , [val "world"]-                , [val "string"]-                , [val "east"]-                ]-  conjureWith args{forceTests=force, maxSize=14} "pig1" pig1'+  conjureFromSpecWith args{maxSize=14} "pig1" pig1Spec     [ pr "ay"     , prif (undefined :: String)     , prim "isVowel" isVowel@@ -657,10 +652,7 @@     , prim ":" ((:) :: Char -> String -> String)     ] -  let force  =  [ [val "hello world"]-                , [val "a string"]-                ]-  conjureWith args{forceTests=force} "gps20c" gps20p+  conjureFromSpec "gps20c" gps20s     [ prim "words" (words :: String -> [String])     , prim "unwords" (unwords :: [String] -> String)     , prim "map" (map :: (String -> String) -> [String] -> [String])@@ -692,11 +684,11 @@   -- GPS Benchmark #22 -- Scrabble Score ---gps22p :: String -> Int-gps22p "a"  =  1-gps22p "hello"  =  8-gps22p "world"  =  9-gps22p "scrabble"  =  14+gps22s :: (String -> Int) -> Bool+gps22s scrabble  =  scrabble "a" == 1+                 && scrabble "hello" == 8+                 && scrabble "world" == 9+                 && scrabble "scrabble" == 14  gps22g :: String -> Int gps22g  =  scrabble@@ -725,13 +717,7 @@  gps22c :: IO () gps22c  =  do-  let force  =  [ [val "a"]-                , [val "hello"]-                , [val "world"]-                , [val "scrabble"]-                ]--  conjureWith args{forceTests=force} "gps22" gps22p+  conjureFromSpec "gps22" gps22s     [ pr (0 :: Int)     , prim "+" ((+) :: Int -> Int -> Int)     , prim "map" (map :: (Int -> Int) -> [Int] -> [Int])@@ -865,13 +851,13 @@   -- GPS Benchmark #29 -- Syllables ---gps29p :: String -> Int-gps29p "pub"  =  1-gps29p "hello"  =  2-gps29p "world"  =  1-gps29p "string"  =  1-gps29p "haskell"  =  2-gps29p "photography"  =  4+gps29s :: (String -> Int) -> Bool+gps29s sys  =  sys "pub" == 1+            && sys "hello" == 2+            && sys "world" == 1+            && sys "string" == 1+            && sys "haskell" == 2+            && sys "photography" == 4  gps29g :: String -> Int gps29g ""  =  0@@ -880,21 +866,13 @@                   else gps29g cs  gps29c :: IO ()-gps29c  =  conjureWith args{forceTests=force} "gps29" gps29p+gps29c  =  conjureFromSpec "gps29" gps29s   [ pr (0 :: Int)   , pr (1 :: Int)   , prim "+" ((+) :: Int->Int->Int)   , prif (undefined :: Int)   , prim "isVowel" isVowel   ]-  where-  force  =  [ [val "pub"]-            , [val "hello"]-            , [val "world"]-            , [val "string"]-            , [val "haskell"]-            , [val "photography"]-            ]   main :: IO ()
bench/gps.out view
@@ -339,7 +339,6 @@ isVowel c  =  False  pig1 :: [Char] -> [Char]--- testing 4 combinations of argument values -- pruning with 5/5 rules -- looking through 2 candidates of size 1 -- looking through 1 candidates of size 2@@ -359,7 +358,6 @@ pig1 (c:cs)  =  if isVowel c then (c:cs) ++ "ay" else cs ++ (c:"ay")  gps20c :: [Char] -> [Char]--- testing 2 combinations of argument values -- pruning with 1/1 rules -- looking through 1 candidates of size 1 -- looking through 1 candidates of size 2@@ -385,7 +383,6 @@ gps21 (x:xs)  =  (if x < 0 then 0 else x):gps21 xs  gps22 :: [Char] -> Int--- testing 4 combinations of argument values -- pruning with 5/9 rules -- looking through 1 candidates of size 1 -- looking through 0 candidates of size 2@@ -460,7 +457,6 @@ gps28 x y z x'  =  x `min` (y `min` (z `min` x'))  gps29 :: [Char] -> Int--- testing 6 combinations of argument values -- pruning with 7/11 rules -- looking through 2 candidates of size 1 -- looking through 2 candidates of size 2
bench/gps2.hs view
@@ -120,12 +120,10 @@ -- considering we're getting input as kebab-case. -- Nevertheless, this one is out of reach performance-wise (and OOM-wise) -gps4p :: String -> String-gps4p "the-stealth-warrior"  =  "theStealthWarrior"---gps4p "The_Stealth_Warrior"  =  "TheStealthWarrior"-gps4p "camel-case"  =  "camelCase"---gps4p "snake_case"  =  "snakeCase"-gps4p "Kebab-Case"  =  "KebabCase"+gps4s :: (String -> String) -> Bool+gps4s g  =  g "the-stealth-warrior" == "theStealthWarrior"+         && g "camel-case" == "camelCase"+         && g "Kebab-Case" == "KebabCase"  gps4g :: String -> String gps4g ""  =  ""@@ -139,15 +137,8 @@  gps4c :: IO () gps4c  =  do-  let force  =  [ [val "the-stealth-warrior"]---              , [val "The_Stealth_Warrior"]-                , [val "camel-case"]---              , [val "snake_case"]-                , [val "Kebab-Case"]-                ]-  conjureWith args{forceTests = force, maxSize=6} "gps4" gps4p+  conjureFromSpecWith args{maxSize=6} "gps4" gps4s     [ pr '-'---  , pr '_'     , pr ("" :: String)     , prim ":" ((:) :: Char -> String -> String)     , prim "==" ((==) :: Char -> Char -> Bool)@@ -179,13 +170,13 @@ gps5p  20  =  [0, 2, 0, 0] gps5p   3  =  [0, 0, 0, 3] -gps5p2 :: [Int] -> Int -> [Int]-gps5p2 [25, 10, 5, 1] 100  =  [4, 0, 0, 0]-gps5p2 [25, 10, 5, 1]  50  =  [2, 0, 0, 0]-gps5p2 [25, 10, 5, 1]  25  =  [1, 0, 0, 0]-gps5p2 [25, 10, 5, 1]  30  =  [1, 0, 1, 0]-gps5p2 [25, 10, 5, 1]  20  =  [0, 2, 0, 0]-gps5p2 [25, 10, 5, 1]   3  =  [0, 0, 0, 3]+gps5s :: ([Int] -> Int -> [Int]) -> Bool+gps5s t  =  t [25, 10, 5, 1] 100 == [4, 0, 0, 0]+         && t [25, 10, 5, 1]  50 == [2, 0, 0, 0]+         && t [25, 10, 5, 1]  25 == [1, 0, 0, 0]+         && t [25, 10, 5, 1]  30 == [1, 0, 1, 0]+         && t [25, 10, 5, 1]  20 == [0, 2, 0, 0]+         && t [25, 10, 5, 1]   3 == [0, 0, 0, 3]  coins :: [Int] coins  =  [25, 10, 5, 1]@@ -204,26 +195,19 @@     [     ] -  let force = [ [val coins, val (100::Int)]-              , [val coins, val ( 50::Int)]-              , [val coins, val ( 25::Int)]-              , [val coins, val ( 30::Int)]-              , [val coins, val ( 20::Int)]-              , [val coins, val (  3::Int)]-              ]-  conjureWith args{forceTests=force} "tell" gps5p2+  conjureFromSpec "tell" gps5s     [ pr ([] :: [Int])     , prim ":" ((:) :: Int -> [Int] -> [Int])     , prim "`div`" (div :: Int -> Int -> Int)     , prim "`mod`" (mod :: Int -> Int -> Int)     ] -  conjureWith args{forceTests=force} "gps5" gps5p+  conjure "gps5" gps5p     [ pr coins     , prim "tell" tell     ] -  conjureWith args{forceTests=force} "gps5" gps5p+  conjure "gps5" gps5p     [ pr (1 :: Int)     , pr (5 :: Int)     , pr (10 :: Int)@@ -568,20 +552,20 @@   ]  -gps21p :: String -> String-gps21p "word"  =  "word"-gps21p "words"  =  "sdrow"-gps21p "word words"  =  "word sdrow"-gps21p "words word"  =  "sdrow word"+gps21s :: (String -> String) -> Bool+gps21s s  =  s "word" == "word"+          && s "words" == "sdrow"+          && s "word words" == "word sdrow"+          && s "words word" == "sdrow word" -spin' :: String -> String-spin' "abc"  =  "abc"-spin' "abcd"  =  "abcd"-spin' "word"  =  "word"-spin' "abcde"  =  "edcba"-spin' "words"  =  "sdrow"-spin' "hello"  =  "olleh"-spin' "world"  =  "dlrow"+spinSpec :: (String -> String) -> Bool+spinSpec spin  =  spin "abc" == "abc"+               && spin "abcd" == "abcd"+               && spin "word" == "word"+               && spin "abcde" == "edcba"+               && spin "words" == "sdrow"+               && spin "hello" == "olleh"+               && spin "world" == "dlrow"  spin :: String -> String spin w  =  if length w >= 5@@ -593,15 +577,7 @@  gps21c :: IO () gps21c  =  do-  let force  =  [ [ val "abc" ]-                , [ val "abcd" ]-                , [ val "word" ]-                , [ val "abcde" ]-                , [ val "words" ]-                , [ val "hello" ]-                , [ val "world" ]-                ]-  conjureWith args{maxSize=12, forceTests=force} "spin" spin'+  conjureFromSpec "spin" spinSpec     [ prim "length"  (length :: String -> Int)     , prim "reverse" (reverse :: String -> String)     , prif (undefined :: String)@@ -609,12 +585,7 @@     , pr (5 :: Int)     ] -  let force  =  [ [ val "word" ]-                , [ val "words" ]-                , [ val "word words" ]-                , [ val "words word" ]-                ]-  conjureWith args{maxSize=12, forceTests=force} "gps21_spinwords" gps21p+  conjureFromSpec "gps21_spinwords" gps21s     [ prim "words"   words     , prim "unwords" unwords     , prim "spin"    (spin :: String -> String)@@ -657,11 +628,11 @@     ]  -gps23p :: String -> String -> String -> String-gps23p "abcd" "abcd" "abcd"  =  "abcd"-gps23p "abcd" "dcba" "abcd"  =  "dcba"-gps23p "abcd" "1234" "abcd"  =  "1234"-gps23p "abcd" "1234" "bacd"  =  "2134"+gps23s :: (String -> String -> String -> String) -> Bool+gps23s s  =  s "abcd" "abcd" "abcd" == "abcd"+          && s "abcd" "dcba" "abcd" == "dcba"+          && s "abcd" "1234" "abcd" == "1234"+          && s "abcd" "1234" "bacd" == "2134"  gps23g :: String -> String -> String -> String -- gps23g f t s  =  map (\c -> fromJust $ c `lookup` zipWith (,) f t) s@@ -669,13 +640,8 @@  gps23c :: IO () gps23c  =  do-  let force = [ [ val "abcd", val "abcd", val "abcd" ]-              , [ val "abcd", val "dcba", val "abcd" ]-              , [ val "abcd", val "1234", val "abcd" ]-              , [ val "abcd", val "1234", val "bacd" ]-              ]   -- cannot conjure, needs lambda-  conjureWith args{forceTests=force} "gps23" gps23p+  conjureFromSpec "gps23" gps23s     [     ] @@ -708,20 +674,15 @@                      then TooMany                      else Tweet (length s) -gps24p_twitter :: String -> Twitter-gps24p_twitter "" =  Empty-gps24p_twitter "abcd"  =  Tweet 4-gps24p_twitter "0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij"  =  Tweet 140-gps24p_twitter "0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghijX"  =  TooMany+gps24s_twitter :: (String -> Twitter) -> Bool+gps24s_twitter twitter  =  twitter "" == Empty+                        && twitter "abcd" == Tweet 4+                        && twitter "0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij" == Tweet 140+                        && twitter "0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghijX" == TooMany  gps24c :: IO () gps24c  =  do-  let force = [ [ val "" ]-              , [ val "abcd" ]-              , [ val "0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij" ]-              , [ val "0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghijX" ]-              ]-  conjureWith args{maxTests=360, forceTests=force} "gps24" gps24p_twitter+  conjureFromSpecWith args{maxTests=360} "gps24" gps24s_twitter     [ pr Empty     , pr TooMany     , prim "Tweet" Tweet
bench/gps2.out view
@@ -47,14 +47,12 @@ cannot conjure  gps3 :: [Char] -> Int--- testing 0 combinations of argument values -- pruning with 0/0 rules -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2 cannot conjure  gps4 :: [Char] -> [Char]--- testing 3 combinations of argument values -- pruning with 13/20 rules -- looking through 2 candidates of size 1 -- looking through 3 candidates of size 2@@ -71,7 +69,6 @@ cannot conjure  tell :: [Int] -> Int -> [Int]--- testing 6 combinations of argument values -- pruning with 0/0 rules -- looking through 2 candidates of size 1 -- looking through 1 candidates of size 2@@ -183,14 +180,12 @@ gps13_leaders (x:xs)  =  if all (x >) xs then x:gps13_leaders xs else gps13_leaders xs  gps14_luhn :: [Int] -> Int--- testing 0 combinations of argument values -- pruning with 0/0 rules -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2 cannot conjure  gps15_mastermind :: () -> ()--- testing 0 combinations of argument values -- pruning with 0/1 rules -- looking through 1 candidates of size 1 gps15_mastermind u  =  u@@ -246,14 +241,12 @@ cannot conjure  gps20 :: [Char] -> Bool--- testing 0 combinations of argument values -- pruning with 0/0 rules -- looking through 0 candidates of size 1 -- looking through 0 candidates of size 2 cannot conjure  spin :: [Char] -> [Char]--- testing 7 combinations of argument values -- pruning with 6/6 rules -- reasoning produced 1 incorrect properties, please re-run with more tests for faster results -- looking through 1 candidates of size 1@@ -267,7 +260,6 @@ spin cs  =  if length cs >= 5 then reverse cs else cs  gps21_spinwords :: [Char] -> [Char]--- testing 4 combinations of argument values -- pruning with 16/16 rules -- reasoning produced 2 incorrect properties, please re-run with more tests for faster results -- looking through 1 candidates of size 1@@ -295,13 +287,11 @@ cannot conjure  gps22 :: Int -> [Char]--- testing 0 combinations of argument values -- pruning with 0/0 rules -- looking through 0 candidates of size 1 cannot conjure  gps23 :: [Char] -> [Char] -> [Char] -> [Char]--- testing 4 combinations of argument values -- pruning with 0/0 rules -- looking through 3 candidates of size 1 -- looking through 12 candidates of size 2@@ -318,7 +308,6 @@ cannot conjure  gps24 :: [Char] -> Twitter--- testing 4 combinations of argument values -- pruning with 4/8 rules -- reasoning produced 4 incorrect properties, please re-run with more tests for faster results -- looking through 2 candidates of size 1
bench/ill-hit.hs view
@@ -14,34 +14,21 @@ sum' [3,4,5]  =  12 sum' [1,2,3,4]  =  10 -sumSpec :: [([Int],Int)]-sumSpec  =  [ [] -= 0-            , [1] -= 1-            , [1,2] -= 3-            , [1,2,3] -= 6-            , [3,4,5] -= 12-            , [1,2,3,4] -= 10-            ]+sumSpec :: ([Int] -> Int) -> Bool+sumSpec sum  =  sum [] == 0+             && sum [1] == 1+             && sum [1,2] == 3+             && sum [1,2,3] == 6+             && sum [3,4,5] == 12+             && sum [1,2,3,4] == 10  main :: IO () main  =  do   -- the following does not hit all 6 defined prims, only 4   conjure "sum" (sum' :: [Int] -> Int) primitives -  -- the following forces 3 argument prims, totaling 6-  conjureWith as "sum" (sum' :: [Int] -> Int) primitives-   -- the following conjures from a spec-  conjure1 "sum" sumSpec primitives--as :: Args-as  =  args-    {  forceTests = map (map val)-                  [ [[1,2]]-                  , [[3,4,5::Int]]-                  , [[1,2,3,4]]-                  ]-    }+  conjureFromSpec "sum" sumSpec primitives  primitives :: [Prim] primitives =
bench/ill-hit.out view
@@ -10,18 +10,6 @@ sum (x:xs)  =  x + sum xs  sum :: [Int] -> Int--- testing 6 combinations of argument values--- pruning with 14/25 rules--- looking through 2 candidates of size 1--- looking through 5 candidates of size 2--- looking through 6 candidates of size 3--- looking through 20 candidates of size 4--- looking through 34 candidates of size 5-sum []  =  0-sum (x:xs)  =  x + sum xs--sum :: [Int] -> Int--- testing 6 combinations of argument values -- pruning with 14/25 rules -- looking through 2 candidates of size 1 -- looking through 5 candidates of size 2
bench/runtime/zero/bench/candidates.runtime view
@@ -1,1 +1,1 @@-9.1+9.2
bench/runtime/zero/bench/gps.runtime view
@@ -1,1 +1,1 @@-23.8+22.8
bench/runtime/zero/bench/gps2.runtime view
@@ -1,1 +1,1 @@-9.5+9.3
bench/runtime/zero/bench/ill-hit.runtime view
@@ -1,1 +1,1 @@-1.3+0.9
bench/runtime/zero/bench/p12.runtime view
@@ -1,1 +1,1 @@-3.2+3.3
bench/runtime/zero/bench/terpret.runtime view
@@ -1,1 +1,1 @@-13.0+13.2
bench/runtime/zero/eg/fib01.runtime view
@@ -1,1 +1,1 @@-4.4+4.5
bench/runtime/zero/eg/fibonacci.runtime view
@@ -1,1 +1,1 @@-8.8+8.2
bench/runtime/zero/eg/list.runtime view
@@ -1,1 +1,1 @@-0.6+0.4
bench/runtime/zero/eg/pow.runtime view
@@ -1,1 +1,1 @@-3.5+3.4
bench/runtime/zero/eg/spec.runtime view
@@ -1,1 +1,1 @@-0.4+1.1
bench/runtime/zero/eg/tree.runtime view
@@ -1,1 +1,1 @@-1.5+1.4
bench/runtime/zero/versions view
@@ -1,4 +1,4 @@-GHC 8.10.4+GHC 8.10.5 leancheck-0.9.10 express-1.0.6 speculate-0.4.14
bench/terpret.hs view
@@ -66,9 +66,9 @@  t3p :: [Bool] -> [Bool] -- t3p [True]  =  [False]-t3p [True,True]  =  [False,True]             --  11 - 1 =  10-t3p [False,True]  =  [True,False]            --  10 - 1 =   1-t3p [False,True,True]  =  [True,False,True]  -- 110 - 1 = 101+t3p [True,True]  =  [False,True]             -- 3-1=2+t3p [False,True]  =  [True,False]            -- 2-1=1+t3p [False,True,True]  =  [True,False,True]  -- 6-1=5  t3g :: [Bool] -> [Bool] t3g []  =  []
+ bench/time view
@@ -0,0 +1,9 @@+#!/bin/bash+#+# bench/time: runs a program, discards stdout and print name and runtime+#+# Copyright (C) 2021 Rudy Matela+# Distributed under the 3-Clause BSD licence (see the file LICENSE).++printf "%-14s  " "$*"+/usr/bin/time -f%e "$@" >/dev/null
changelog.md view
@@ -2,6 +2,16 @@ ============================  +v0.5.0+------++* allow synthesizing/conjuring from properties with `conjureFromSpec`;+* complete Haddock documentation;+* remove several unused functions;+* add stub `conjurableDerive` functions;+* Makefile: add targets to run GPS(2) and TerpreT benches.++ v0.4.4 ------ 
code-conjure.cabal view
@@ -3,14 +3,10 @@ -- Copyright (C) 2021 Rudy Matela -- Distributed under the 3-Clause BSD licence (see the file LICENSE). name:                code-conjure-version:             0.4.4-synopsis:            conjure Haskell functions out of partial definitions+version:             0.5.0+synopsis:            synthesize Haskell functions out of partial definitions description:-  Conjure is a tool that produces Haskell functions out of partial definitions.-  .-  This is currently an experimental tool in its early stages,-  don't expect much from its current version.-  It is just a piece of curiosity in its current state.+  Conjure is a tool that synthesizes Haskell functions out of partial definitions.  homepage:            https://github.com/rudymatela/conjure#readme license:             BSD3@@ -48,6 +44,7 @@                   , bench/runtime/zero/proto/*.runtime                   , bench/runtime/zero/versions                   , bench/versions+                  , bench/time                   , test/sdist tested-with: GHC==9.0            , GHC==8.10@@ -66,15 +63,15 @@ source-repository this   type:            git   location:        https://github.com/rudymatela/conjure-  tag:             v0.4.4+  tag:             v0.5.0  library   exposed-modules: Conjure                  , Conjure.Conjurable+                 , Conjure.Conjurable.Derive                  , Conjure.Engine                  , Conjure.Expr                  , Conjure.Prim-                 , Conjure.Spec                  , Conjure.Utils                  , Conjure.Defn   other-extensions: TemplateHaskell, CPP@@ -82,14 +79,14 @@                , leancheck >= 0.9.10                , template-haskell                , speculate >= 0.4.14-               , express >= 1.0.6+               , express >= 1.0.8   hs-source-dirs:      src   default-language:    Haskell2010  test-suite expr   type:                exitcode-stdio-1.0   main-is:             expr.hs-  other-modules:       Test, Test.ListableExpr, Test.Candidates+  other-modules:       Test, Test.ListableExpr   hs-source-dirs:      test   build-depends:       base >= 4 && < 5, leancheck, express, speculate, code-conjure   default-language:    Haskell2010@@ -97,7 +94,7 @@ test-suite defn   type:                exitcode-stdio-1.0   main-is:             defn.hs-  other-modules:       Test, Test.ListableExpr, Test.Candidates+  other-modules:       Test, Test.ListableExpr   hs-source-dirs:      test   build-depends:       base >= 4 && < 5, leancheck, express, speculate, code-conjure   default-language:    Haskell2010@@ -105,7 +102,7 @@ test-suite conjurable   type:                exitcode-stdio-1.0   main-is:             conjurable.hs-  other-modules:       Test, Test.ListableExpr, Test.Candidates+  other-modules:       Test, Test.ListableExpr   hs-source-dirs:      test   build-depends:       base >= 4 && < 5, leancheck, express, speculate, code-conjure   default-language:    Haskell2010@@ -113,7 +110,15 @@ test-suite utils   type:                exitcode-stdio-1.0   main-is:             utils.hs-  other-modules:       Test, Test.ListableExpr, Test.Candidates+  other-modules:       Test, Test.ListableExpr+  hs-source-dirs:      test+  build-depends:       base >= 4 && < 5, leancheck, express, speculate, code-conjure+  default-language:    Haskell2010++test-suite derive+  type:                exitcode-stdio-1.0+  main-is:             derive.hs+  other-modules:       Test, Test.ListableExpr   hs-source-dirs:      test   build-depends:       base >= 4 && < 5, leancheck, express, speculate, code-conjure   default-language:    Haskell2010
eg/dupos.hs view
@@ -3,6 +3,7 @@ -- Copyright (C) 2021 Rudy Matela -- Distributed under the 3-Clause BSD licence (see the file LICENSE). import Conjure+import Test.LeanCheck  -- needed for duplicatesSpec only  duplicates :: [Int] -> [Int] -- Eq a => [a] -> [a] duplicates []  =  []@@ -21,6 +22,12 @@ duplicates' [1,0,1,0,1]  =  [0,1] duplicates' [0,1,2,1]  =  [1] +duplicatesSpec :: ([Int] -> [Int]) -> Bool+duplicatesSpec duplicates  =  and+  [ holds 360 $ \x xs -> (count (x ==) xs > 1) == elem x (duplicates xs)+  , holds 360 $ \x xs -> count (x ==) (duplicates xs) <= 1+  ]  where  count p  =  length . filter p+ positionsFrom :: Int -> Int -> [Int] -> [Int] positionsFrom n x  =  from n   where@@ -54,6 +61,15 @@   --                       else duplicates xs                              -- 17   -- within reach performance wise.   conjureWith args{maxSize=18} "duplicates" duplicates'+    [ pr ([] :: [Int])+    , prim "not" not+    , prim "&&" (&&)+    , prim ":" ((:) :: Int -> [Int] -> [Int])+    , prim "elem" (elem :: Int -> [Int] -> Bool)+    , prif (undefined :: [Int])+    ]++  conjureFromSpecWith args{maxSize=18} "duplicates" duplicatesSpec     [ pr ([] :: [Int])     , prim "not" not     , prim "&&" (&&)
eg/dupos.out view
@@ -21,6 +21,28 @@ duplicates []  =  [] duplicates (x:xs)  =  if elem x xs && not (elem x (duplicates xs)) then x:duplicates xs else duplicates xs +duplicates :: [Int] -> [Int]+-- pruning with 21/26 rules+-- looking through 2 candidates of size 1+-- looking through 1 candidates of size 2+-- looking through 1 candidates of size 3+-- looking through 2 candidates of size 4+-- looking through 1 candidates of size 5+-- looking through 2 candidates of size 6+-- looking through 3 candidates of size 7+-- looking through 8 candidates of size 8+-- looking through 16 candidates of size 9+-- looking through 25 candidates of size 10+-- looking through 36 candidates of size 11+-- looking through 65 candidates of size 12+-- looking through 141 candidates of size 13+-- looking through 322 candidates of size 14+-- looking through 644 candidates of size 15+-- looking through 1189 candidates of size 16+-- looking through 2189 candidates of size 17+duplicates []  =  []+duplicates (x:xs)  =  if elem x xs && not (elem x (duplicates xs)) then x:duplicates xs else duplicates xs+ positionsFrom :: Int -> A -> [A] -> [Int] -- testing 360 combinations of argument values -- pruning with 5/10 rules
eg/list.hs view
@@ -38,36 +38,21 @@  main :: IO () main = do-  -- length xs  =  if null xs then 0 else 1 + length (tail xs)-  --               1  2    3       4      5 6 7       8    9   conjure "length" length'     [ pr (0 :: Int)     , pr (1 :: Int)     , prim "+" ((+) :: Int -> Int -> Int)-    , prim "tail" (tail :: [Int] -> [Int])-    , prim "null" (null :: [Int] -> Bool)     ] -  -- reverse xs  =  if null xs then [] else reverse (tail xs) ++ [head xs]-  --                1  2    3       4       5        6    7   8  9 10 11 12-  -- needs size 11 with unit   conjure "reverse" reverse'     [ pr ([] :: [Int])     , prim "unit" ((:[]) :: Int -> [Int])     , prim "++" ((++) :: [Int] -> [Int] -> [Int])-    , prim "head" (head :: [Int] -> Int)-    , prim "tail" (tail :: [Int] -> [Int])-    , prim "null" (null :: [Int] -> Bool)     ] -  -- xs ++ ys  =  if null xs then ys else head xs:(tail xs ++ ys)-  --              1  2    3       4       5    6 7  8   9  10 11   conjure "++" (+++)     [ pr ([] :: [Int])     , prim ":" ((:) :: Int -> [Int] -> [Int])-    , prim "head" (head :: [Int] -> Int)-    , prim "tail" (tail :: [Int] -> [Int])-    , prim "null" (null :: [Int] -> Bool)     ]    -- now through fold@@ -93,20 +78,13 @@     , prim "." ((.) :: ([Int]->[Int]->[Int]) -> (Int->[Int]) -> Int -> [Int] -> [Int])     ] -  -- now through fold-  -- xs ++ ys  =  foldr (:) ys xs   conjure "++" (+++)     [ pr ([] :: [Int])     , prim ":" ((:) :: Int -> [Int] -> [Int])     , prim "foldr" (foldr :: (Int -> [Int] -> [Int]) -> [Int] -> [Int] -> [Int])     ] -  -- intercalate-  -- xs \/ ys  =  if null xs then ys else head xs : (ys \/ tail xs)   conjure "\\/" (\/)     [ pr ([] :: [Int])     , prim ":" ((:) :: Int -> [Int] -> [Int])-    , prim "head" (head :: [Int] -> Int)-    , prim "tail" (tail :: [Int] -> [Int])-    , prim "null" (null :: [Int] -> Bool)     ]
eg/list.out view
@@ -4,32 +4,32 @@ -- looking through 2 candidates of size 1 -- looking through 4 candidates of size 2 -- looking through 3 candidates of size 3--- looking through 13 candidates of size 4+-- looking through 11 candidates of size 4 -- looking through 10 candidates of size 5 length []  =  0 length (x:xs)  =  length xs + 1  reverse :: [Int] -> [Int] -- testing 360 combinations of argument values--- pruning with 12/13 rules+-- pruning with 3/3 rules -- looking through 2 candidates of size 1--- looking through 3 candidates of size 2--- looking through 11 candidates of size 3--- looking through 24 candidates of size 4--- looking through 60 candidates of size 5--- looking through 152 candidates of size 6+-- looking through 1 candidates of size 2+-- looking through 3 candidates of size 3+-- looking through 2 candidates of size 4+-- looking through 5 candidates of size 5+-- looking through 7 candidates of size 6 reverse []  =  [] reverse (x:xs)  =  reverse xs ++ unit x  (++) :: [Int] -> [Int] -> [Int] -- testing 360 combinations of argument values--- pruning with 4/4 rules+-- pruning with 0/0 rules -- looking through 3 candidates of size 1--- looking through 11 candidates of size 2--- looking through 38 candidates of size 3--- looking through 136 candidates of size 4--- looking through 517 candidates of size 5--- looking through 1606 candidates of size 6+-- looking through 8 candidates of size 2+-- looking through 11 candidates of size 3+-- looking through 44 candidates of size 4+-- looking through 116 candidates of size 5+-- looking through 80 candidates of size 6 [] ++ xs  =  xs (x:xs) ++ ys  =  x:(xs ++ ys) @@ -67,13 +67,13 @@  (\/) :: [Int] -> [Int] -> [Int] -- testing 360 combinations of argument values--- pruning with 4/4 rules+-- pruning with 0/0 rules -- looking through 3 candidates of size 1--- looking through 11 candidates of size 2--- looking through 38 candidates of size 3--- looking through 136 candidates of size 4--- looking through 517 candidates of size 5--- looking through 1606 candidates of size 6+-- looking through 8 candidates of size 2+-- looking through 11 candidates of size 3+-- looking through 44 candidates of size 4+-- looking through 116 candidates of size 5+-- looking through 80 candidates of size 6 [] \/ xs  =  xs (x:xs) \/ ys  =  x:ys \/ xs 
eg/spec.hs view
@@ -2,16 +2,36 @@ -- -- Adapted from Colin Runciman's example "ListFuns" import Conjure+import Test.LeanCheck (holds, exists) import Prelude hiding (sum)  -sumSpec :: Spec1 [Int] Int-sumSpec  =-  [ []      -= 0-  , [1,2]   -= 3-  , [3,4,5] -= 12+squareSpec :: (Int -> Int) -> Bool+squareSpec square  =  square 0 == 0+                   && square 1 == 1+                   && square 2 == 4++squarePrimitives :: [Prim]+squarePrimitives  =+  [ pr (0::Int)+  , pr (1::Int)+  , prim "+" ((+) :: Int -> Int -> Int)+  , prim "*" ((*) :: Int -> Int -> Int)   ] +squarePropertySpec :: (Int -> Int) -> Bool+squarePropertySpec square  =  and+  [ holds n $ \x -> square x >= x+  , holds n $ \x -> square x >= 0+  , exists n $ \x -> square x > x+  ]  where  n = 60+++sumSpec :: ([Int] -> Int) -> Bool+sumSpec sum  =  sum []      == 0+             && sum [1,2]   == 3+             && sum [3,4,5] == 12+ -- hoping for something like -- sum xs  =  if null xs then 0 else head xs + sum (tail xs) @@ -25,12 +45,10 @@   ]  -appSpec :: Spec2 [Int] [Int] [Int]-appSpec  =-  [ (,) []      [0,1]   -= [0,1]-  , (,) [2,3]   []      -= [2,3]-  , (,) [4,5,6] [7,8,9] -= [4,5,6,7,8,9]-  ]+appSpec :: ([Int] -> [Int] -> [Int]) -> Bool+appSpec (++)  =  []      ++ [0,1]   == [0,1]+              && [2,3]   ++ []      == [2,3]+              && [4,5,6] ++ [7,8,9] == [4,5,6,7,8,9]  -- hoping for something like -- app xs ys = if null xs then ys else head xs : app (tail xs) ys@@ -46,5 +64,7 @@  main :: IO () main = do-  conjure1 "sum" sumSpec sumPrimitives-  conjure2 "++"  appSpec appPrimitives+  conjureFromSpec "square" squareSpec squarePrimitives+  conjureFromSpec "square" squarePropertySpec squarePrimitives+  conjureFromSpec "sum" sumSpec sumPrimitives+  conjureFromSpec "++"  appSpec appPrimitives
eg/spec.out view
@@ -1,5 +1,18 @@+square :: Int -> Int+-- 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+square x  =  x * x++square :: Int -> Int+-- 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+square x  =  x * x+ sum :: [Int] -> Int--- testing 3 combinations of argument values -- pruning with 4/8 rules -- looking through 1 candidates of size 1 -- looking through 2 candidates of size 2@@ -10,7 +23,6 @@ sum (x:xs)  =  x + sum xs  (++) :: [Int] -> [Int] -> [Int]--- testing 3 combinations of argument values -- pruning with 3/3 rules -- looking through 2 candidates of size 1 -- looking through 4 candidates of size 2
eg/tree.hs view
@@ -14,7 +14,7 @@  -- TODO: remove the following import -- and fix build on GHC 7.10 and 7.8--- the generation fo -: and ->>>: somehow fails.+-- the generation of -: and ->>>: somehow fails. import Test.LeanCheck.Utils  data Tree  =  Leaf
mk/depend.mk view
@@ -8,406 +8,411 @@   mk/toplibs bench/candidates.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/candidates.hs bench/gps2: \   bench/gps2.hs \   mk/toplibs bench/gps2.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/gps2.hs bench/gps: \   bench/gps.hs \   mk/toplibs bench/gps.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/gps.hs bench/ill-hit: \   bench/ill-hit.hs \   mk/toplibs bench/ill-hit.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/ill-hit.hs bench/longshot: \   bench/longshot.hs \   mk/toplibs bench/longshot.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/longshot.hs bench/lowtests: \   bench/lowtests.hs \   mk/toplibs bench/lowtests.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/lowtests.hs bench/p12: \   bench/p12.hs \   mk/toplibs bench/p12.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/p12.hs bench/p30: \   bench/p30.hs \   mk/toplibs bench/p30.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/p30.hs bench/self: \   bench/self.hs \   mk/toplibs bench/self.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/self.hs bench/take-drop: \   bench/take-drop.hs \   mk/toplibs bench/take-drop.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/take-drop.hs bench/terpret: \   bench/terpret.hs \   mk/toplibs bench/terpret.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   bench/terpret.hs eg/arith: \   eg/arith.hs \   mk/toplibs eg/arith.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/arith.hs eg/bools: \   eg/bools.hs \   mk/toplibs eg/bools.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/bools.hs eg/count: \   eg/count.hs \   mk/toplibs eg/count.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/count.hs eg/dupos: \   eg/dupos.hs \   mk/toplibs eg/dupos.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/dupos.hs eg/factorial: \   eg/factorial.hs \   mk/toplibs eg/factorial.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/factorial.hs eg/fib01: \   eg/fib01.hs \   mk/toplibs eg/fib01.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/fib01.hs eg/fibonacci: \   eg/fibonacci.hs \   mk/toplibs eg/fibonacci.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/fibonacci.hs eg/gcd: \   eg/gcd.hs \   mk/toplibs eg/gcd.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/gcd.hs eg/ints: \   eg/ints.hs \   mk/toplibs eg/ints.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/ints.hs eg/list: \   eg/list.hs \   mk/toplibs eg/list.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/list.hs eg/pow: \   eg/pow.hs \   mk/toplibs eg/pow.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/pow.hs eg/replicate: \   eg/replicate.hs \   mk/toplibs eg/replicate.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/replicate.hs eg/setelem: \   eg/setelem.hs \   mk/toplibs eg/setelem.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/setelem.hs eg/sort: \   eg/sort.hs \   mk/toplibs eg/sort.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/sort.hs eg/spec: \   eg/spec.hs \   mk/toplibs eg/spec.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/spec.hs eg/subset: \   eg/subset.hs \   mk/toplibs eg/subset.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/subset.hs eg/tapps: \   eg/tapps.hs \   mk/toplibs eg/tapps.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/tapps.hs eg/tree: \   eg/tree.hs \   mk/toplibs eg/tree.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   eg/tree.hs mk/All.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   mk/All.hs mk/Toplibs.o: \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs \   mk/Toplibs.hs proto/u-conjure.o: \   proto/u-conjure.hs proto/u-conjure: \   proto/u-conjure.hs \   mk/toplibs+src/Conjure/Conjurable/Derive.o: \+  src/Conjure/Utils.hs \+  src/Conjure/Expr.hs \+  src/Conjure/Defn.hs \+  src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs src/Conjure/Conjurable.o: \   src/Conjure/Utils.hs \   src/Conjure/Expr.hs \@@ -429,125 +434,120 @@   src/Conjure/Expr.hs src/Conjure.o: \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \-  src/Conjure/Conjurable.hs+  src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs src/Conjure/Prim.o: \   src/Conjure/Utils.hs \   src/Conjure/Prim.hs \   src/Conjure/Expr.hs \   src/Conjure/Defn.hs \   src/Conjure/Conjurable.hs-src/Conjure/Spec.o: \-  src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \-  src/Conjure/Prim.hs \-  src/Conjure/Expr.hs \-  src/Conjure/Engine.hs \-  src/Conjure/Defn.hs \-  src/Conjure/Conjurable.hs src/Conjure/Utils.o: \   src/Conjure/Utils.hs test/conjurable.o: \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   test/conjurable.hs \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \-  src/Conjure/Conjurable.hs+  src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs test/conjurable: \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   test/conjurable.hs \   mk/toplibs test/defn.o: \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   test/defn.hs \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \-  src/Conjure/Conjurable.hs+  src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs test/defn: \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   test/defn.hs \   mk/toplibs+test/derive.o: \+  test/Test.hs \+  test/Test/ListableExpr.hs \+  test/derive.hs \+  src/Conjure/Utils.hs \+  src/Conjure/Prim.hs \+  src/Conjure.hs \+  src/Conjure/Expr.hs \+  src/Conjure/Engine.hs \+  src/Conjure/Defn.hs \+  src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs+test/derive: \+  test/Test.hs \+  test/Test/ListableExpr.hs \+  test/derive.hs \+  mk/toplibs test/expr.o: \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   test/expr.hs \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \-  src/Conjure/Conjurable.hs+  src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs test/expr: \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   test/expr.hs \   mk/toplibs-test/Test/Candidates.o: \-  test/Test/Candidates.hs \-  src/Conjure/Utils.hs \-  src/Conjure/Expr.hs test/Test/ListableExpr.o: \   test/Test/ListableExpr.hs test/Test.o: \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \-  src/Conjure/Conjurable.hs+  src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs test/Test: \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   mk/toplibs test/utils.o: \   test/utils.hs \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   src/Conjure/Utils.hs \-  src/Conjure/Spec.hs \   src/Conjure/Prim.hs \   src/Conjure.hs \   src/Conjure/Expr.hs \   src/Conjure/Engine.hs \   src/Conjure/Defn.hs \-  src/Conjure/Conjurable.hs+  src/Conjure/Conjurable.hs \+  src/Conjure/Conjurable/Derive.hs test/utils: \   test/utils.hs \   test/Test.hs \   test/Test/ListableExpr.hs \-  test/Test/Candidates.hs \   mk/toplibs
mk/haskell.mk view
@@ -52,6 +52,7 @@ PKGNAME = $(shell cat *.cabal | grep "^name:"    | sed -e "s/name: *//")  HADDOCK_HAS = haddock --help | grep -q --+HADDOCK_FILTER ?= cat   # Implicit rules@@ -111,7 +112,8 @@ 	  $(shell $(HADDOCK_HAS) --package-name          && echo "--package-name=$(PKGNAME)" ) \ 	  $(shell $(HADDOCK_HAS) --hyperlinked-source    && echo "--hyperlinked-source"      ) \ 	  $(shell $(HADDOCK_HAS) --no-print-missing-docs && echo --no-print-missing-docs     ) \-	  $(HADDOCKFLAGS)+	  $(HADDOCKFLAGS) | \+	$(HADDOCK_FILTER)  clean-cabal: 	rm -rf dist/ dist-newstyle/ cabal.project.local cabal.project.local~
src/Conjure.hs view
@@ -27,7 +27,7 @@ -- >   , pr (1::Int) -- >   , prim "+" ((+) :: Int -> Int -> Int) -- >   , prim "*" ((*) :: Int -> Int -> Int)--- > ]+-- >   ] -- -- Step 3: call conjure and see your generated function: --@@ -59,16 +59,8 @@   , value  -- * Conjuring from a specification-  , Spec1-  , Spec2-  , Spec3-  , (-=)-  , conjure1-  , conjure2-  , conjure3-  , conjure1With-  , conjure2With-  , conjure3With+  , conjureFromSpec+  , conjureFromSpecWith  -- * When using custom types   , Conjurable (conjureExpress, conjureEquality, conjureTiers, conjureCases, conjureSubTypes)@@ -78,6 +70,9 @@   , conjureType   , Name (..)   , Express (..)+  , deriveConjurable+  , deriveConjurableIfNeeded+  , deriveConjurableCascading  -- * Pure interfaces   , conjpure@@ -89,6 +84,6 @@ where  import Conjure.Engine-import Conjure.Spec import Conjure.Conjurable import Conjure.Prim+import Conjure.Conjurable.Derive
src/Conjure/Conjurable.hs view
@@ -4,7 +4,7 @@ -- License     : 3-Clause BSD  (see the file LICENSE) -- Maintainer  : Rudy Matela <rudy@matela.com.br> ----- This module is part of 'Conjure'.+-- This module is part of "Conjure". -- -- This defines the 'Conjurable' typeclass -- and utilities involving it.@@ -58,7 +58,14 @@  -- | Single reification of some functions over a type as 'Expr's. ----- A hole, an equality function and tiers.+-- This is a sixtuple, in order:+--+-- 1. a hole encoded as an 'Expr';+-- 2. the '==' function encoded as an 'Expr' when available;+-- 3. 'tiers' of enumerated test values encoded as 'Expr's when available;+-- 4. infinite list of potential variable names;+-- 5. boolean indicating whether the type is atomic;+-- 6. the 'conjureSize' function encoded as an 'Expr'. type Reification1  =  (Expr, Maybe Expr, Maybe [[Expr]], [String], Bool, Expr)  -- | A reification over a collection of types.@@ -127,35 +134,55 @@    -- | Returns 'Just' the '==' function encoded as an 'Expr' when available   --   or 'Nothing' otherwise.+  --+  -- Use 'reifyEquality' when defining this.   conjureEquality :: a -> Maybe Expr   conjureEquality _  =  Nothing    -- | Returns 'Just' 'tiers' of values encoded as 'Expr's when possible   --   or 'Nothing' otherwise.+  --+  -- Use 'reifyTiers' when defining this.   conjureTiers :: a -> Maybe [[Expr]]   conjureTiers _  =  Nothing    conjureSubTypes :: a -> Reification   conjureSubTypes _  =  id +  -- | Returns an if-function encoded as an 'Expr'.   conjureIf :: a -> Expr   conjureIf   =  ifFor +  -- | Returns a top-level case breakdown.   conjureCases :: a -> [Expr]   conjureCases _  =  []    conjureArgumentCases :: a -> [[Expr]]   conjureArgumentCases _  =  [] +  -- | Returns the (recursive) size of the given value.   conjureSize :: a -> Int   conjureSize _  =  0 +  -- | Returns a function that deeply reencodes an expression when possible.+  --   ('id' when not available.)+  --+  -- Use 'reifyExpress' when defining this.   conjureExpress :: a -> Expr -> Expr    conjureEvaluate :: (Expr->Expr) -> Int -> Defn -> Expr -> Maybe a   conjureEvaluate  =  devaluate  +-- | To be used in the implementation of 'conjureSubTypes'.+--+-- > instance ... => Conjurable <Type> where+-- >   ...+-- >   conjureSubTypes x  =  conjureType (field1 x)+-- >                      .  conjureType (field2 x)+-- >                      .  ...+-- >                      .  conjureType (fieldN x)+-- >   ... conjureType :: Conjurable a => a -> Reification conjureType x ms  =   if hole x `elem` [h | (h,_,_,_,_,_) <- ms]@@ -168,16 +195,31 @@ -- The use of nubOn above is O(n^2). -- So long as there is not a huge number of subtypes of a, so we're fine. +-- | Conjures a 'Reification1' for a 'Conjurable' type.+--+-- This is used in the implementation of 'conjureReification'. conjureReification1 :: Conjurable a => a -> Reification1 conjureReification1 x  =  (hole x, conjureEquality x, conjureTiers x, names x, null $ conjureCases x, value "conjureSize" (conjureSize -:> x)) +-- | Conjures a list of 'Reification1'+--   for a 'Conjurable' type, its subtypes and 'Bool'.+--+-- This is used in the implementation of+-- 'conjureHoles',+-- 'conjureMkEquation',+-- 'conjureAreEqual',+-- 'conjureTiersFor',+-- 'conjureIsDeconstructor',+-- 'conjureNamesFor',+-- 'conjureIsUnbreakable',+-- etc. conjureReification :: Conjurable a => a -> [Reification1] conjureReification x  =  nubConjureType x [conjureReification1 bool]   where   bool :: Bool   bool  =  error "conjureReification: evaluated proxy boolean value (definitely a bug)" --- | Reifies equality to be used in a conjurable type.+-- | Reifies equality '==' in a 'Conjurable' type instance. -- -- This is to be used -- in the definition of 'conjureEquality'@@ -203,6 +245,16 @@ reifyTiers :: (Listable a, Show a, Typeable a) => a -> Maybe [[Expr]] reifyTiers  =  Just . mkExprTiers +-- | Reifies the 'expr' function in a 'Conjurable' type instance.+--+-- This is to be used+-- in the definition of 'conjureExpress'+-- of 'Conjurable' typeclass instances.+--+-- > instance ... => Conjurable <Type> where+-- >   ...+-- >   conjureExpress  =  reifyExpress+-- >   ... reifyExpress :: (Express a, Show a) => a -> Expr -> Expr reifyExpress a e  =  case value "expr" (expr -:> a) $$ e of   Nothing -> e         -- TODO: consider throwing an error@@ -211,12 +263,20 @@ mkExprTiers :: (Listable a, Show a, Typeable a) => a -> [[Expr]] mkExprTiers a  =  mapT val (tiers -: [[a]]) +-- | Computes a list of holes encoded as 'Expr's+--   from a 'Conjurable' functional value.+--+-- (cf. 'Conjure.Prim.cjHoles') conjureHoles :: Conjurable f => f -> [Expr] conjureHoles f  =  [eh | (eh,_,Just _,_,_,_) <- conjureReification f] +-- | 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] +-- | Given a 'Conjurable' functional value,+--   computes a function that checks whether two 'Expr's are equal+--   up to a given number of tests. conjureAreEqual :: Conjurable f => f -> Int -> Expr -> Expr -> Bool conjureAreEqual f maxTests  =  (===)   where@@ -225,6 +285,8 @@   isTrue  =  all (errorToFalse . eval False) . gs   gs  =  take maxTests . grounds (conjureTiersFor f) +-- | Compute 'tiers' of values encoded as 'Expr's+--   of the type of the given 'Expr'. conjureTiersFor :: Conjurable f => f -> Expr -> [[Expr]] conjureTiersFor f e  =  tf allTiers   where@@ -235,6 +297,7 @@                       ((e':_):_) | typ e' == typ e -> etiers                       _                            -> tf etc +-- | Compute variable names for the given 'Expr' type. conjureNamesFor :: Conjurable f => f -> Expr -> [String] conjureNamesFor f e  =  head                      $  [ns | (eh, _, _, ns, _, _) <- conjureReification f, typ e == typ eh]@@ -244,6 +307,9 @@ conjureMostGeneralCanonicalVariation f  =  canonicalizeWith (conjureNamesFor f)                                         .  fastMostGeneralVariation +-- | Checks if an unary function encoded as an 'Expr' is a deconstructor.+--+-- (cf. 'conjureIsDeconstruction') conjureIsDeconstructor :: Conjurable f => f -> Int -> Expr -> Bool conjureIsDeconstructor f maxTests e  =  case as of   [] -> False@@ -259,8 +325,14 @@     esz e  =  eval (0::Int) (sz :$ e)     is e'  =  errorToFalse $ esz (e :$ e') < esz e' --- the result does not increase the size for at least half the time--- the result decreases in size for at least a third of the time+-- | Checks if an expression is a deconstruction.+--+-- There should be a single 'hole' in the expression.+--+-- 1. The result does not increase the size for at least half the time.+-- 2. The result decreases in size for at least a third of the time.+--+-- (cf. 'conjureIsDeconstructor') conjureIsDeconstruction :: Conjurable f => f -> Int -> Expr -> Bool conjureIsDeconstruction f maxTests ed  =  length (holes ed) == 1                                        && typ h == typ ed@@ -280,6 +352,11 @@                $  e `match` ed   err  =  error "conjureIsDeconstructor: the impossible happened" +-- | Compute candidate deconstructions from an 'Expr'.+--+-- This is used in the implementation of+-- 'Conjure.Engine.candidateDefnsC' and 'Conjure.Engine.candidateExprs'+-- followed by 'conjureIsDeconstruction'. candidateDeconstructionsFrom :: Expr -> [Expr] candidateDeconstructionsFrom e  =   [ e'@@ -289,6 +366,7 @@   , length (holes e') == 1   ] +-- | Checks if an 'Expr' is of an unbreakable type. conjureIsUnbreakable :: Conjurable f => f -> Expr -> Bool conjureIsUnbreakable f e  =  head   [is | (h,_,_,_,is,_) <- conjureReification f, typ h == typ e]@@ -326,6 +404,10 @@ (==:) :: (a -> a -> Bool) -> a -> (a -> a -> Bool) (==:)  =  const +-- the reconstruction of equality functions for polymorphic types+-- such as [a], (a,b), Maybe a, Either a b+-- is only needed so we don't impose an Eq restriction on the type context.+ instance (Conjurable a, Listable a, Express a, Show a) => Conjurable [a] where   conjureExpress   =  reifyExpress   conjureSubTypes xs  =  conjureType (head xs)@@ -466,6 +548,10 @@ resTy :: (a -> b) -> b resTy _  =  undefined +-- | Evaluates a 'Defn' into a regular Haskell value+--   returning 'Nothing' when there's a type mismatch.+--+-- The integer argument indicates the limit of recursive evaluations. cevaluate :: Conjurable f => Int -> Defn -> Maybe f cevaluate mx defn  =  mr   where@@ -473,27 +559,59 @@   exprExpr  =  conjureExpress $ fromJust mr   (ef':_)  =  unfoldApp . fst $ head defn +-- | Evaluates a 'Defn' into a regular Haskell value+--   returning the given default value when there's a type mismatch.+--+-- The integer argument indicates the limit of recursive evaluations. ceval :: Conjurable f => Int -> f -> Defn -> f ceval mx z  =  fromMaybe z . cevaluate mx +-- | Evaluates a 'Defn' into a regular Haskell value+--   raising an error there's a type mismatch.+--+-- The integer argument indicates the limit of recursive evaluations. cevl :: Conjurable f => Int -> Defn -> f cevl mx  =  ceval mx err   where   err  =  error "cevl: type mismatch" +-- | Computes a complete application for the given function.+--+-- > > conjureApplication "not" not+-- > not p :: Bool+--+-- > > conjureApplication "+" ((+) :: Int -> Int -> Int)+-- > x + y :: Int+--+-- (cf. 'conjureVarApplication') conjureApplication :: Conjurable f => String -> f -> Expr conjureApplication  =  conjureWhatApplication value +-- | Computes a complete application for a variable+--   of the same type of the given function.+--+-- > > conjureVarApplication "not" not+-- > not p :: Bool+--+-- > > conjureVarApplication "+" ((+) :: Int -> Int -> Int)+-- > x + y :: Int+--+-- (cf. 'conjureApplication') conjureVarApplication :: Conjurable f => String -> f -> Expr conjureVarApplication  =  conjureWhatApplication var +-- | Used in the implementation of 'conjureApplication' and 'conjureVarApplication'. conjureWhatApplication :: Conjurable f => (String -> f -> Expr) -> String -> f -> Expr conjureWhatApplication what nm f  =  mostGeneralCanonicalVariation . foldApp                                   $  what nf f : zipWith varAsTypeOf nas (conjureArgumentHoles f)   where   (nf:nas)  =  words nm ++ repeat "" -conjurePats :: Conjurable f => [Expr] -> String -> f -> [[[Expr]]]+-- | Computes tiers of sets of patterns for the given function.+--+-- > > conjurePats [zero] "f" (undefined :: Int -> Int)+-- > [[[f x :: Int]],[[f 0 :: Int,f x :: Int]]]+conjurePats :: Conjurable f => [Expr] -> String -> f -> [[ [Expr] ]] conjurePats es nm f  =  mapT (map mkApp . prods) $ cs   where   mkApp  =  foldApp . (ef:)
+ src/Conjure/Conjurable/Derive.hs view
@@ -0,0 +1,167 @@+{-# LANGUAGE TemplateHaskell, CPP #-}+-- |+-- Module      : Conjure.Conjurable.Derive+-- Copyright   : (c) 2019-2021 Rudy Matela+-- License     : 3-Clause BSD  (see the file LICENSE)+-- Maintainer  : Rudy Matela <rudy@matela.com.br>+--+-- Allows automatic derivation of 'Conjurable' typeclass instances.+module Conjure.Conjurable.Derive+  ( deriveConjurable+  , deriveConjurableCascading+  , deriveConjurableIfNeeded+  )+where++import Test.LeanCheck+import Test.LeanCheck.Derive+import Test.LeanCheck.Utils+import Conjure.Expr hiding (mkName, Name, isInstanceOf)+import Conjure.Conjurable hiding (Name)+import Data.Express.Utils (primeCycle)+import Data.Express.Utils.TH++import Control.Monad+import Data.Char+import Data.List+import Language.Haskell.TH.Lib++#if __GLASGOW_HASKELL__ < 710+import Data.Functor ((<$>))+#endif++-- | Derives an 'Conjurable' instance for the given type 'Name'.+--+-- This function needs the @TemplateHaskell@ extension.+--+-- If '-:', '->:', '->>:', '->>>:', ... are not in scope,+-- this will derive them as well.+--+-- For now,+-- this function only derives+-- 'conjureEquality',+-- 'conjureTiers' and+-- 'conjureExpress'+-- and does not derive+-- 'conjureSubTypes',+-- 'conjureArgumentCases' and+-- 'conjureSize'.+-- These will be added in future versions.+-- If you plan to use features that depend on these functionalities,+-- please define your instances manually.+deriveConjurable :: Name -> DecsQ+deriveConjurable  =  deriveWhenNeededOrWarn ''Conjurable reallyDerive+  where+  reallyDerive  =  reallyDeriveConjurableWithRequisites++-- | Same as 'deriveConjurable' but does not warn when instance already exists+--   ('deriveConjurable' is preferable).+--+-- For now,+-- this function only derives+-- 'conjureEquality',+-- 'conjureTiers' and+-- 'conjureExpress'+-- and does not derive+-- 'conjureSubTypes',+-- 'conjureArgumentCases' and+-- 'conjureSize'.+-- These will be added in future versions.+-- If you plan to use features that depend on these functionalities,+-- please define your instances manually.+deriveConjurableIfNeeded :: Name -> DecsQ+deriveConjurableIfNeeded  =  deriveWhenNeeded ''Conjurable reallyDerive+  where+  reallyDerive  =  reallyDeriveConjurableWithRequisites++-- | Derives a 'Conjurable' instance for a given type 'Name'+--   cascading derivation of type arguments as well.+--+-- For now,+-- this function only derives+-- 'conjureEquality',+-- 'conjureTiers' and+-- 'conjureExpress'+-- and does not derive+-- 'conjureSubTypes',+-- 'conjureArgumentCases' and+-- 'conjureSize'.+-- These will be added in future versions.+-- If you plan to use features that depend on these functionalities,+-- please define your instances manually.+deriveConjurableCascading :: Name -> DecsQ+deriveConjurableCascading  =  deriveWhenNeeded ''Conjurable reallyDerive+  where+  reallyDerive t  =  concat+                 <$> sequence [ deriveListableCascading t+                              , deriveNameCascading t+                              , deriveExpressCascading t+                              , reallyDeriveConjurableCascading t ]++reallyDeriveConjurableWithRequisites :: Name -> DecsQ+reallyDeriveConjurableWithRequisites t  =  concat <$>+  sequence [ deriveListableIfNeeded t+           , deriveNameIfNeeded t+           , deriveExpressIfNeeded t+           , reallyDeriveConjurable t ]++reallyDeriveConjurable :: Name -> DecsQ+reallyDeriveConjurable t  =  do+  isEq <- t `isInstanceOf` ''Eq+  isOrd <- t `isInstanceOf` ''Ord+  (nt,vs) <- normalizeType t+#if __GLASGOW_HASKELL__ >= 710+  cxt <- sequence [ [t| $(conT c) $(return v) |]+#else+  -- template-haskell <= 2.9.0.0:+  cxt <- sequence [ classP c [return v]+#endif+                  | c <- [''Conjurable, ''Listable, ''Express] ++ [''Eq | isEq] ++ [''Ord | isOrd]+                  , v <- vs]+  cs <- typeConstructorsArgNames t+  asName <- newName "x"+  let withTheReturnTypeOfs = deriveWithTheReturnTypeOfs $ [length ns | (_,ns) <- cs]+  let inst = [d| instance Conjurable $(return nt) where+                   conjureExpress   =  reifyExpress+                   conjureEquality  =  reifyEquality+                   conjureTiers     =  reifyTiers |]+  -- withTheReturnTypeOfs |++| (cxt |=>| inst)+  cxt |=>| inst+-- TODO: derive conjureCases+-- TODO: derive conjureSize+-- TODO: derive conjureSubTypes (cf. Extrapolate.subInstances)++-- Not only really derive Conjurable instances,+-- but cascade through argument types.+reallyDeriveConjurableCascading :: Name -> DecsQ+reallyDeriveConjurableCascading  =  reallyDeriveCascading ''Conjurable reallyDeriveConjurable++deriveWithTheReturnTypeOfs :: [Int] -> DecsQ+deriveWithTheReturnTypeOfs  =+  fmap concat . mapM deriveWithTheReturnTypeOf . nubSort++deriveWithTheReturnTypeOf :: Int -> DecsQ+deriveWithTheReturnTypeOf n  =  do+  mf <- lookupValueName name+  case mf of+    Nothing -> reallyDeriveWithTheReturnTypeOf n+    Just _  -> return []+  where+  name  =  "-" ++ replicate n '>' ++ ":"++reallyDeriveWithTheReturnTypeOf :: Int -> DecsQ+reallyDeriveWithTheReturnTypeOf n  =  do+  td <- sigD name theT+  vd <- [d| $(varP name) = const |]+  return $ td:vd+  where+  theT  =  bind [t| $(theFunT) -> $(last vars) -> $(theFunT) |]+  theFunT  =  foldr1 funT vars+  funT t1 t2  =  [t| $(t1) -> $(t2) |]+  vars  =  map (varT . mkName) . take (n+1) . primeCycle $ map (:"") ['a'..'z']+  name  =  mkName $ "-" ++ replicate n '>' ++ ":"+#if __GLASGOW_HASKELL__ >= 800+  bind  =  id -- unbound variables are automatically bound+#else+  bind  =  toBoundedQ+#endif
src/Conjure/Defn.hs view
@@ -4,7 +4,7 @@ -- License     : 3-Clause BSD  (see the file LICENSE) -- Maintainer  : Rudy Matela <rudy@matela.com.br> ----- This module is part of 'Conjure'.+-- This module is part of "Conjure". -- -- This module exports the 'Defn' type synonym and utilities involving it. --@@ -33,9 +33,30 @@ import Control.Applicative ((<$>)) -- for older GHCs import Test.LeanCheck.Utils ((-:>)) -- for toDynamicWithDefn +-- | A function definition as a list of top-level case bindings ('Bndn').+--+-- Here is an example using the notation from "Data.Express.Fixtures":+--+-- > sumV :: Expr+-- > sumV  =  var "sum" (undefined :: [Int] -> Int)+-- >+-- > (=-) = (,)+-- > infixr 0 =-+-- >+-- > sumDefn :: Defn+-- > sumDefn  =  [ sum' nil           =-  zero+-- >             , sum' (xx -:- xxs)  =-  xx -+- (sumV :$ xxs)+-- >             ]  where  sum' e  =  sumV :$ e type Defn  =  [Bndn]++-- | A single binding in a definition ('Defn'). type Bndn  =  (Expr,Expr) +-- | Pretty-prints a 'Defn' as a 'String':+--+-- > > putStr $ showDefn sumDefn+-- > sum []  =  0+-- > sum (x:xs)  =  x + sum xs showDefn :: Defn -> String showDefn  =  unlines . map show1   where@@ -43,8 +64,37 @@  type Memo  =  [(Expr, Maybe Dynamic)] --- | Evaluates an 'Expr' using the given 'Defn' as definition+-- | Evaluates an 'Expr' to a 'Dynamic' value+--   using the given 'Defn' as definition --   when a recursive call is found.+--+-- Arguments:+--+-- 1. a function that deeply reencodes an expression (cf. 'expr')+-- 2. the maximum number of recursive evaluations+-- 3. a 'Defn' to be used when evaluating the given 'Expr'+-- 4. an 'Expr' to be evaluated+--+-- This function cannot be used to evaluate a functional value for the given 'Defn'+-- and can only be used when occurrences of the given 'Defn' are fully applied.+--+-- The function the deeply reencodes an 'Expr' can be defined using+-- functionality present in "Conjure.Conjurable".  Here's a quick-and-dirty version+-- that is able to reencode 'Bool's, 'Int's and their lists:+--+-- > exprExpr :: Expr -> Expr+-- > exprExpr  =  conjureExpress (undefined :: Bool -> [Bool] -> Int -> [Int] -> ())+--+-- The maximum number of recursive evaluations counts in two ways:+--+-- 1. the maximum number of entries in the recursive-evaluation memo table;+-- 2. the maximum number of terminal values considered (but in this case the+--    limit is multiplied by the _size_ of the given 'Defn'.+--+-- These could be divided into two separate parameters but+-- then there would be an extra _dial_ to care about...+--+-- (cf. 'devaluate', 'deval', 'devl') toDynamicWithDefn :: (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe Dynamic toDynamicWithDefn exprExpr mx cx  =  fmap (\(_,_,d) -> d) . re (mx * sum (map (size . snd) cx)) []   where@@ -98,18 +148,49 @@                           Just (n', m', d2) -> (n',m',) <$> dynApply d1 d2   _ $$ _               =  Nothing +-- | Evaluates an 'Expr' expression into 'Just' a regular Haskell value+--   using a 'Defn' definition when it is found.+--   If there's a type-mismatch, this function returns 'Nothing'.+--+-- This function requires a 'Expr'-deep-reencoding function+-- and a limit to the number of recursive evaluations.+--+-- (cf. 'toDynamicWithDefn', 'deval', 'devl') devaluate :: Typeable a => (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe a devaluate ee n fxpr e  =  toDynamicWithDefn ee n fxpr e >>= fromDynamic +-- | Evaluates an 'Expr' expression into a regular Haskell value+--   using a 'Defn' definition when it is found in the given expression.+--   If there's a type-mismatch, this function return a default value.+--+-- This function requires a 'Expr'-deep-reencoding function+-- and a limit to the number of recursive evaluations.+--+-- (cf. 'toDynamicWithDefn', 'devaluate', devl') deval :: Typeable a => (Expr -> Expr) -> Int -> Defn -> a -> Expr -> a deval ee n fxpr x  =  fromMaybe x . devaluate ee n fxpr +-- | Like 'deval' but only works for when the given 'Defn' definition+--   has no case breakdowns.+--+-- In other words, this only works when the given 'Defn' is a singleton list+-- whose first value of the only element is a simple application without+-- constructors. devalFast :: Typeable a => (Expr -> Expr) -> Int -> Defn -> a -> Expr -> a devalFast _ n [defn] x  =  reval defn n x +-- | Evaluates an 'Expr' expression into a regular Haskell value+--   using a 'Defn' definition when it is found in the given expression.+--   If there's a type-mismatch, this raises an error.+--+-- This function requires a 'Expr'-deep-reencoding function+-- and a limit to the number of recursive evaluations.+--+-- (cf. 'toDynamicWithDefn', 'devaluate', deval') devl :: Typeable a => (Expr -> Expr) -> Int -> Defn -> Expr -> a devl ee n fxpr  =  deval ee n fxpr (error "devl: incorrect type?") +-- | Returns whether the given definition 'apparentlyTerminates'. defnApparentlyTerminates :: Defn -> Bool defnApparentlyTerminates [(efxs, e)]  =  apparentlyTerminates efxs e defnApparentlyTerminates _  =  True
src/Conjure/Engine.hs view
@@ -4,7 +4,7 @@ -- License     : 3-Clause BSD  (see the file LICENSE) -- Maintainer  : Rudy Matela <rudy@matela.com.br> ----- An internal module of 'Conjure',+-- An internal module of "Conjure", -- a library for Conjuring function implementations -- from tests or partial definitions. -- (a.k.a.: functional inductive programming)@@ -15,15 +15,22 @@   , Args(..)   , args   , conjureWith+  , conjureFromSpec+  , conjureFromSpecWith+  , conjure0+  , conjure0With   , conjpure   , conjpureWith+  , conjpureFromSpec+  , conjpureFromSpecWith+  , conjpure0+  , conjpure0With   , candidateExprs   , candidateDefns   , candidateDefns1   , candidateDefnsC   , conjureTheory   , conjureTheoryWith-  , deconstructions   , module Data.Express   , module Data.Express.Fixtures   , module Test.Speculate.Engine@@ -69,12 +76,13 @@ -- >   , pr (1::Int) -- >   , prim "+" ((+) :: Int -> Int -> Int) -- >   , prim "*" ((*) :: Int -> Int -> Int)--- > ]+-- >   ] -- -- The conjure function does the following: -- -- > > conjure "square" square primitives -- > square :: Int -> Int+-- > -- pruning with 14/25 rules -- > -- testing 3 combinations of argument values -- > -- looking through 3 candidates of size 1 -- > -- looking through 3 candidates of size 2@@ -86,6 +94,51 @@ conjure  =  conjureWith args  +-- | Conjures an implementation from a function specification.+--+-- This function works like 'conjure' but instead of receiving a partial definition+-- it receives a boolean filter / property about the function.+--+-- For example, given:+--+-- > squareSpec :: (Int -> Int) -> Bool+-- > squareSpec square  =  square 0 == 0+-- >                    && square 1 == 1+-- >                    && square 2 == 4+--+-- Then:+--+-- > > conjureFromSpec "square" squareSpec primitives+-- > square :: Int -> Int+-- > -- 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+-- > square x  =  x * x+--+-- This allows users to specify QuickCheck-style properties,+-- here is an example using LeanCheck:+--+-- > import Test.LeanCheck (holds, exists)+-- >+-- > squarePropertySpec :: (Int -> Int) -> Bool+-- > squarePropertySpec square  =  and+-- >   [ holds n $ \x -> square x >= x+-- >   , holds n $ \x -> square x >= 0+-- >   , exists n $ \x -> square x > x+-- >   ]  where  n = 60+conjureFromSpec :: Conjurable f => String -> (f -> Bool) -> [Prim] -> IO ()+conjureFromSpec  =  conjureFromSpecWith args+++-- | Synthesizes an implementation from both a partial definition and a+--   function specification.+--+--   This works like the functions 'conjure' and 'conjureFromSpec' combined.+conjure0 :: Conjurable f => String -> f -> (f -> Bool) -> [Prim] -> IO ()+conjure0  =  conjure0With args++ -- | Like 'conjure' but allows setting the maximum size of considered expressions --   instead of the default value of 12. --@@ -109,7 +162,6 @@   , 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-  , forceTests            :: [[Expr]]  -- ^ force tests   }  @@ -134,7 +186,6 @@   , requireDescent         =  True   , usePatterns            =  True   , showTheory             =  False-  , forceTests             =  []   }  @@ -142,9 +193,20 @@ -- -- > conjureWith args{maxSize = 11} "function" function [...] conjureWith :: Conjurable f => Args -> String -> f -> [Prim] -> IO ()-conjureWith args nm f es  =  do+conjureWith args nm f  =  conjure0With args nm f (const True)++-- | Like 'conjureFromSpec' but allows setting options through 'Args'/'args'.+--+-- > conjureFromSpecWith args{maxSize = 11} "function" spec [...]+conjureFromSpecWith :: Conjurable f => Args -> String -> (f -> Bool) -> [Prim] -> IO ()+conjureFromSpecWith args nm p  =  conjure0With args nm undefined p++-- | Like 'conjure0' but allows setting options through 'Args'/'args'.+conjure0With :: Conjurable f => Args -> String -> f -> (f -> Bool) -> [Prim] -> IO ()+conjure0With args nm f p es  =  do   print (var (head $ words nm) f)-  putStrLn $ "-- testing " ++ show (length ts) ++ " combinations of argument values"+  when (length ts > 0) $+    putStrLn $ "-- testing " ++ show (length ts) ++ " combinations of argument values"   putStrLn $ "-- pruning with " ++ show nRules ++ "/" ++ show nREs ++ " rules"   when (showTheory args) $ do     putStrLn $ "{-"@@ -166,31 +228,52 @@       []     ->  pr (n+1) rs       (i:_)  ->  putStrLn $ showDefn i   rs  =  zip iss css-  (iss, css, ts, thy)  =  conjpureWith args nm f es+  (iss, css, ts, thy)  =  conjpure0With args nm f p es   nRules  =  length (rules thy)   nREs  =  length (equations thy) + nRules   -- | Like 'conjure' but in the pure world. ----- Returns a triple with:+-- Returns a quadruple with: -- -- 1. tiers of implementations--- 2. tiers of candidate bodies (right type)--- 3. tiers of candidate expressions (any type)--- 4. a list of tests+-- 2. tiers of candidates+-- 3. a list of tests+-- 4. the underlying theory conjpure :: Conjurable f => String -> f -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy) conjpure =  conjpureWith args +-- | Like 'conjureFromSpec' but in the pure world.  (cf. 'conjpure')+conjpureFromSpec :: Conjurable f => String -> (f -> Bool) -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy)+conjpureFromSpec  =  conjpureFromSpecWith args +-- | Like 'conjure0' but in the pure world.  (cf. 'conjpure')+conjpure0 :: Conjurable f => String -> f -> (f -> Bool) -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy)+conjpure0 =  conjpure0With args+ -- | Like 'conjpure' but allows setting options through 'Args' and 'args'. conjpureWith :: Conjurable f => Args -> String -> f -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy)-conjpureWith args@(Args{..}) nm f es  =  (implementationsT, candidatesT, tests, thy)+conjpureWith args nm f  =  conjpure0With args nm f (const True)++-- | Like 'conjureFromSpecWith' but in the pure world.  (cf. 'conjpure')+conjpureFromSpecWith :: Conjurable f => Args -> String -> (f -> Bool) -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy)+conjpureFromSpecWith args nm p  =  conjpure0With args nm undefined p++-- | Like 'conjpure0' but allows setting options through 'Args' and 'args'.+--+-- This is where the actual implementation resides.  The functions+-- 'conjpure', 'conjpureWith', 'conjpureFromSpec', 'conjpureFromSpecWith',+-- 'conjure', 'conjureWith', 'conjureFromSpec', 'conjureFromSpecWith' and+-- 'conjure0' all refer to this.+conjpure0With :: Conjurable f => Args -> String -> f -> (f -> Bool) -> [Prim] -> ([[Defn]], [[Defn]], [Expr], Thy)+conjpure0With args@(Args{..}) nm f p es  =  (implementationsT, candidatesT, tests, thy)   where   tests  =  [ffxx //- bs | bs <- dbss]   implementationsT  =  filterT implements candidatesT   implements fx  =  defnApparentlyTerminates fx                  && requal fx ffxx vffxx+                 && errorToFalse (p (cevl maxEvalRecursions fx))   candidatesT  =  take maxSize candidatesTT   (candidatesTT, thy)  =  candidateDefns args nm f es   ffxx   =  conjureApplication nm f@@ -205,18 +288,18 @@    bss, dbss :: [[(Expr,Expr)]]   bss  =  take maxSearchTests $ groundBinds (conjureTiersFor f) ffxx-  fbss  =  [zip xxs vs | vs <- forceTests, isWellTyped $ foldApp (rrff:vs)]-  dbss  =  take maxTests-        $  ([bs | bs <- bss, errorToFalse . eval False $ e //- bs] \\ fbss)-        ++ fbss+  dbss  =  take maxTests [bs | bs <- bss, errorToFalse . eval False $ e //- bs]     where     e  =  ffxx -==- ffxx  +-- | Just prints the underlying theory found by "Test.Speculate"+--   without actually synthesizing a function. conjureTheory :: Conjurable f => String -> f -> [Prim] -> IO () conjureTheory  =  conjureTheoryWith args  +-- | Like 'conjureTheory' but allows setting options through 'Args'/'args'. conjureTheoryWith :: Conjurable f => Args -> String -> f -> [Prim] -> IO () conjureTheoryWith args nm f es  =  do   putStrLn $ "theory with " ++ (show . length $ rules thy) ++ " rules and "@@ -442,28 +525,6 @@   isNotConstruction (p,e) | isVar p    =  e == p || e `isDecOf` p                           | otherwise  =  size e <= size p -- TODO: allow filter and id somehow -- TODO: improve this function with better isNotConstruction---candidatesTD :: (Expr -> Bool) -> Expr -> [Expr] -> [[Expr]]-candidatesTD keep h primitives  =  filterT (not . hasHole)-                                $  town [[h]]-  where-  most = mostGeneralCanonicalVariation--  town :: [[Expr]] -> [[Expr]]-  town ((e:es):ess) | keep (most e)  =  [[e]] \/ town (expand e \/ (es:ess))-                    | otherwise      =  town (es:ess)-  town ([]:ess)  =  []:town ess-  town []  =  []--  expand :: Expr -> [[Expr]]-  expand e  =  case holesBFS e of-    [] -> []-    (h:_) -> mapT (fillBFS e) (replacementsFor h)--  replacementsFor :: Expr -> [[Expr]]-  replacementsFor h  =  filterT (\e -> typ e == typ h)-                     $  primitiveApplications primitives   -- hardcoded filtering rules
src/Conjure/Expr.hs view
@@ -17,21 +17,14 @@   , recursexpr   , apparentlyTerminates   , mayNotEvaluateArgument-  , applicationOld   , compareSimplicity   , ifFor-  , primitiveHoles-  , primitiveApplications   , valuesBFS   , holesBFS   , fillBFS-  , showEq-  , lhs-  , rhs   , ($$**)   , ($$|<)   , possibleHoles-  , isDeconstructionE   , revaluate   , reval   , useMatches@@ -179,15 +172,6 @@ mayNotEvaluateArgument (Value "||" ce :$ _)       =  True mayNotEvaluateArgument _                          =  False -applicationOld :: Expr -> [Expr] -> Maybe Expr-applicationOld ff es  =  appn ff-  where-  appn ff-    | isFun ff   =  case [e | Just (_ :$ e) <- (map (ff $$)) es] of-                    [] -> Nothing  -- could not find type representative in es-                    (e:_) -> appn (ff :$ holeAsTypeOf e)-    | otherwise  =  Just ff- -- | Creates an if 'Expr' of the type of the given proxy. -- -- > > ifFor (undefined :: Int)@@ -206,23 +190,9 @@ exs >$$< eys  =  catMaybes [ex $$ ey | ex <- exs, ey <- eys] -- TODO: move >$$< into Data.Express? -primitiveHoles :: [Expr] -> [Expr]-primitiveHoles prims  =  sort $ ph hs-  where-  hs  =  nub $ map holeAsTypeOf prims-  ph  =  iterateUntil (==) ps-  ps es  =  nub $ es ++ sq es-  sq es  =  nub $ map holeAsTypeOf $ es >$$< es--- FIXME: the function above is quite inefficient.---        Should run fast for a small number of types,---        but if this number increases runtime may start---        to become significant.--primitiveApplications :: [Expr] -> [[Expr]]-primitiveApplications prims  =  takeWhile (not . null)-                             $  iterate (>$$< primitiveHoles prims) prims---- lists terminal values in BFS order+-- | Lists terminal values in BFS order.+--+-- (cf. 'values', 'holesBFS', 'fillBFS') valuesBFS :: Expr -> [Expr] valuesBFS  =  concat . bfs   where@@ -230,10 +200,15 @@   bfs (ef :$ ex)  =  [] : mzip (bfs ef) (bfs ex)   bfs e  =  [[e]] --- lists holes in BFS order+-- | Lists holes in BFS order.+--+-- (cf. 'holes', 'valuesBFS', 'fillBFS') holesBFS :: Expr -> [Expr] holesBFS  =  filter isHole . valuesBFS +-- | Fills holes in BFS order.+--+-- (cf. 'fill', 'valuesBFS', 'fillBFS') fillBFS :: Expr -> Expr -> Expr fillBFS e e'  =  fst (f e)   where@@ -251,19 +226,38 @@       | otherwise                    =  (e, Nothing) -- TODO: move BFS functions into Express? -showEq :: Expr -> String-showEq (((Value "==" _) :$ lhs) :$ rhs)  =  showExpr lhs ++ "  =  " ++ showExpr rhs-showEq e  =  "not an Eq: " ++ show e--lhs, rhs :: Expr -> Expr-lhs (((Value "==" _) :$ e) :$ _)  =  e-rhs (((Value "==" _) :$ _) :$ e)  =  e---- Debug: application that always works+-- | Like '$$' but always works regardless of type.+--+-- /Warning:/ just like ':$', this may produce ill-typed expressions.+--+-- > > zero $$** zero+-- > Just (0 0 :: ill-typed # Int $ Int #)+--+-- Together with '$$|<', this function is unused+-- but is useful when experiment with the source+-- to see the effect of type-corrected+-- on pruning the search space.+--+-- (cf. '$$', '$$|<') ($$**) :: Expr -> Expr -> Maybe Expr e1 $$** e2  =  Just $ e1 :$ e2 --- Debug: application that works for the correct kinds+-- | Like '$$' but relaxed to work on correct kinds.+--+-- > > ordE $$|< zero+-- > Just (ord 0 :: ill-typed # Char -> Int $ Int #)+--+-- > > zero $$|< zero+-- > Nothing+--+-- /Warning:/ just like ':$', this may produce ill-typed expressions.+--+-- Together with '$$**', this function is unused+-- but is useful when experiment with the source+-- to see the effect of type-corrected+-- on pruning the search space.+--+-- (cf. '$$', '$$**') ($$|<) :: Expr -> Expr -> Maybe Expr e1 $$|< e2  =  if isFunTy t1 && tyArity (argumentTy t1) == tyArity t2                then Just $ e1 :$ e2@@ -276,17 +270,36 @@   ktyp (e1 :$ e2)  =  resultTy (ktyp e1)   ktyp e  =  typ e ++-- | Lists all distinct holes that are possible with the given 'Expr's.+--+-- > > possibleHoles [zero, one, plus]+-- > [_ :: Int,_ :: Int -> Int,_ :: Int -> Int -> Int]+--+-- > > possibleHoles [ae, ordE]+-- > [_ :: Char,_ :: Int,_ :: Char -> Int] possibleHoles :: [Expr] -> [Expr] possibleHoles  =  nubSort . ph . nubSort . map holeAsTypeOf   where   ph hs  =  case nubSort $ hs ++ [holeAsTypeOf hfx | hf <- hs, hx <- hs, Just hfx <- [hf $$ hx]] of             hs' | hs' == hs -> hs                 | otherwise -> ph hs'-  nubSort  =  nub . sort -- TODO: this is O(n^2), make this O(n log n)   -- -- Expression enumeration -- -- +-- | Enumerate applications between values of the given list of primitives+--   and of the given expressions's type.+--+-- __Arguments:__+--+-- 1. an 'Expr' whose type we are interested in+-- 2. a filtering function, returning 'True' for the expressions to keep+-- 3. a list of primitives to be used in building expression.+--+-- __Result:__ a potentially infinite list of list of enumerated expressions+--+-- The enumeration here is type-directed for performance reasons. enumerateAppsFor :: Expr -> (Expr -> Bool) -> [Expr] -> [[Expr]] enumerateAppsFor h keep es  =  for h   where@@ -303,18 +316,20 @@           ,  typ h == typ hfx           ] +-- | Given an expression whose holes are /all of the same type/+--   and an enumeration of 'Expr's of this same type,+--   enumerate all possible fillings of the original expression+--   with the 'Expr's in the enumeration. enumerateFillings :: Expr -> [[Expr]] -> [[Expr]] enumerateFillings e  =  mapT (fill e)                      .  products                      .  replicate (length $ holes e) --- Like 'isDeconstruction' but lifted over the 'Expr' type.-isDeconstructionE :: [Expr] -> Expr -> Expr -> Bool---                   [a] -> (a -> Bool) -> (a -> a) -> Bool-isDeconstructionE [] _ _  =  error "isDeconstructionE: empty list of test values"-isDeconstructionE es ez ed | all isIllTyped [f :$ e | e <- es, f <- [ez,ed]]  =  error "isDeconstructionE: types do not match"-isDeconstructionE es ez ed  =  isDeconstruction es (eval False . (ez :$)) (ed :$)-+-- | Evaluates an 'Expr' to a 'Dynamic' value+--   using the given recursive definition and+--   maximum number of recursive calls.+--+-- (cf. 'Conjure.Defn.toDynamicWithDefn') recursiveToDynamic :: (Expr,Expr) -> Int -> Expr -> Maybe Dynamic recursiveToDynamic (efxs, ebody) n  =  fmap (\(_,_,d) -> d) . re (n * size ebody) n   where@@ -353,9 +368,22 @@                           Just (m', n', d2) -> (m',n',) <$> dynApply d1 d2   _ $$ _               =  Nothing +-- | Evaluates an 'Expr' to a regular Haskell value+--   using the given recursive definition and+--   maximum number of recursive calls.+--   If there's a type mismatch, this function returns 'Nothing'.+--+-- (cf. 'evaluate', 'Conjure.Defn.devaluate') revaluate :: Typeable a => (Expr,Expr) -> Int -> Expr -> Maybe a revaluate dfn n e  =  recursiveToDynamic dfn n e >>= fromDynamic +-- | Evaluates an 'Expr' to a regular Haskell value+--   using the given recursive definition and+--   maximum number of recursive calls.+--   If there's a type mismatch,+--   this function returns the given default value.+--+-- (cf. 'eval', 'Conjure.Defn.deval') reval :: Typeable a => (Expr,Expr) -> Int -> a -> Expr -> a reval dfn n x  =  fromMaybe x . revaluate dfn n @@ -386,6 +414,10 @@   | (e',es') <- choicesThat (\e' _ -> any (`elem` vars e') (vars e)) es'   ] +-- | Turns all variables of an expression into holes.+--+-- > > rehole (xx -+- yy)+-- > _ + _ :: Int rehole :: Expr -> Expr rehole (e1 :$ e2)    = rehole e1 :$ rehole e2 rehole e | isVar e   = "" `varAsTypeOf` e
src/Conjure/Prim.hs view
@@ -4,7 +4,7 @@ -- License     : 3-Clause BSD  (see the file LICENSE) -- Maintainer  : Rudy Matela <rudy@matela.com.br> ----- This module is part of 'Conjure'.+-- This module is part of "Conjure". -- -- The 'Prim' type and utilities involving it. --@@ -57,16 +57,28 @@ -- Conjure.Conjurable but need a list of Prims instead of a Conjurable -- representative. +-- | Computes a list of 'Reification1's from a list of 'Prim's.+--+-- This function mirrors functionality of 'conjureReification'. cjReification :: [Prim] -> [Reification1] cjReification ps  =  nubOn (\(eh,_,_,_,_,_) -> eh)                   $  foldr (.) id (map snd ps) [conjureReification1 bool] +-- | Computes a list of holes encoded as 'Expr's from a list of 'Prim's.+--+-- This function mirrors functionality from 'conjureHoles'. cjHoles :: [Prim] -> [Expr] cjHoles ps  =  [eh | (eh,_,Just _,_,_,_) <- cjReification ps] +-- | Computes a function that equates two 'Expr's from a list of 'Prim's.+--+-- This function mirrors functionality from 'conjureMkEquation'. cjMkEquation :: [Prim] -> Expr -> Expr -> Expr cjMkEquation ps  =  mkEquation [eq | (_,Just eq,_,_,_,_) <- cjReification ps] +-- | Given a list of 'Prim's,+--   computes a function that checks whether two 'Expr's are equal+--   up to a given number of tests. cjAreEqual :: [Prim] -> Int -> Expr -> Expr -> Bool cjAreEqual ps maxTests  =  (===)   where@@ -75,6 +87,11 @@   isTrue  =  all (errorToFalse . eval False) . gs   gs  =  take maxTests . grounds (cjTiersFor ps) +-- | Given a list of 'Prim's,+--   returns a function that given an 'Expr'+--   will return tiers of test 'Expr' values.+--+-- This is used in 'cjAreEqual'. cjTiersFor :: [Prim] -> Expr -> [[Expr]] cjTiersFor ps e  =  tf allTiers   where
− src/Conjure/Spec.hs
@@ -1,191 +0,0 @@--- |--- Module      : Conjure.Spec--- Copyright   : (c) 2021 Rudy Matela--- License     : 3-Clause BSD  (see the file LICENSE)--- Maintainer  : Rudy Matela <rudy@matela.com.br>------ An internal module of 'Conjure',--- a library for Conjuring function implementations--- from tests or partial definitions.--- (a.k.a.: functional inductive programming)-module Conjure.Spec-  ( Spec1-  , Spec2-  , Spec3-  , (-=)-  , conjure1-  , conjure2-  , conjure3-  , conjure1With-  , conjure2With-  , conjure3With-  )-where--import Conjure.Engine-import Conjure.Conjurable-import Conjure.Utils-import Conjure.Prim----- | A partial specification of a function with one argument:------ > sumSpec :: Spec1 [Int] Int--- > sumSpec  =--- >   [ []      -= 0--- >   , [1,2]   -= 3--- >   , [3,4,5] -= 12--- >   ]------ To be passed as one of the arguments to 'conjure1'.-type Spec1 a b     = [(a,b)]----- | A partial specification of a function with two arguments:------ > appSpec :: Spec2 [Int] [Int] [Int]--- > appSpec  =--- >   [ (,) []      [0,1]   -= [0,1]--- >   , (,) [2,3]   []      -= [2,3]--- >   , (,) [4,5,6] [7,8,9] -= [4,5,6,7,8,9]--- >   ]------ To be passed as one of the arguments to 'conjure2'.-type Spec2 a b c   = [((a,b),c)]----- | A partial specification of a function with three arguments.------ To be passed as one of the arguments to 'conjure3'-type Spec3 a b c d = [((a,b,c),d)]----- | To be used when constructing specifications:---   'Spec1',---   'Spec2' and---   'Spec3'.-(-=) :: a -> b -> (a,b)-(-=)  =  (,)----- | Conjures a one argument function from a specification.------ Given:------ > sumSpec :: Spec1 [Int] Int--- > sumSpec  =--- >   [ []      -= 0--- >   , [1,2]   -= 3--- >   , [3,4,5] -= 12--- >   ]------ > sumPrimitives :: [Prim]--- > sumPrimitives  =--- >   [ prim "null" (null :: [Int] -> Bool)--- >   , pr (0::Int)--- >   , prim "+"    ((+) :: Int -> Int -> Int)--- >   , prim "head" (head :: [Int] -> Int)--- >   , prim "tail" (tail :: [Int] -> [Int])--- >   ]------ Then:------ > > conjure1 "sum" sumSpec sumPrimitives--- > sum :: [Int] -> Int--- > -- testing 3 combinations of argument values--- > -- ...--- > -- looking through 189/465 candidates of size 10--- > xs ++ ys  =  if null xs then ys else head xs:(tail xs ++ ys)------ (cf. 'Spec1', 'conjure1With')-conjure1 :: (Eq a, Eq b, Show a, Express a, Conjurable a, Conjurable b)-         => String -> Spec1 a b -> [Prim] -> IO ()-conjure1  =  conjure1With args----- | Conjures a two argument function from a specification.------ Given:------ > appSpec :: Spec2 [Int] [Int] [Int]--- > appSpec  =--- >   [ (,) []      [0,1]   -= [0,1]--- >   , (,) [2,3]   []      -= [2,3]--- >   , (,) [4,5,6] [7,8,9] -= [4,5,6,7,8,9]--- >   ]------ > appPrimitives :: [Expr]--- > appPrimitives =--- >   [ prim "null" (null :: [Int] -> Bool)--- >   , prim ":"    ((:) :: Int -> [Int] -> [Int])--- >   , prim "head" (head :: [Int] -> Int)--- >   , prim "tail" (tail :: [Int] -> [Int])--- >   ]------ Then:------ > > conjure2 "++" appSpec appPrimitives--- > (++) :: [Int] -> [Int] -> [Int]--- > -- testing 3 combinations of argument values--- > -- ...--- > -- looking through 26166/57090 candidates of size 11--- > xs ++ ys  =  if null xs then ys else head xs:(tail xs ++ ys)------ (cf. 'Spec2', 'conjure2With')-conjure2 :: ( Conjurable a, Eq a, Show a, Express a-            , Conjurable b, Eq b, Show b, Express b-            , Conjurable c, Eq c-            ) => String -> Spec2 a b c -> [Prim] -> IO ()-conjure2  =  conjure2With args----- | Conjures a three argument function from a specification.------ (cf. 'Spec3', 'conjure3With')-conjure3 :: ( Conjurable a, Eq a, Show a, Express a-            , Conjurable b, Eq b, Show b, Express b-            , Conjurable c, Eq c, Show c, Express c-            , Conjurable d, Eq d-            ) => String -> Spec3 a b c d -> [Prim] -> IO ()-conjure3  =  conjure3With args----- | Like 'conjure1' but allows setting options through 'Args'/'args'.-conjure1With :: (Eq a, Eq b, Show a, Express a, Conjurable a, Conjurable b)-             => Args -> String -> Spec1 a b -> [Prim] -> IO ()-conjure1With args nm bs  =  conjureWith args{forceTests=ts} nm (mkFun1 bs)-  where-  ts = [[val x] | (x,_) <- bs]----- | Like 'conjure2' but allows setting options through 'Args'/'args'.-conjure2With :: ( Conjurable a, Eq a, Show a, Express a-                , Conjurable b, Eq b, Show b, Express b-                , Conjurable c, Eq c-                ) => Args -> String -> Spec2 a b c -> [Prim] -> IO ()-conjure2With args nm bs  =  conjureWith args{forceTests=ts} nm (mkFun2 bs)-  where-  ts = [[val x, val y] | ((x,y),_) <- bs]----- | Like 'conjure3' but allows setting options through 'Args'/'args'.-conjure3With :: ( Conjurable a, Eq a, Show a, Express a-                , Conjurable b, Eq b, Show b, Express b-                , Conjurable c, Eq c, Show c, Express c-                , Conjurable d, Eq d-                ) => Args -> String -> Spec3 a b c d -> [Prim] -> IO ()-conjure3With args nm bs  =  conjureWith args{forceTests=ts} nm (mkFun3 bs)-  where-  ts = [[val x, val y, val z] | ((x,y,z),_) <- bs]---mkFun1 :: Eq a => [(a,b)] -> a -> b-mkFun1 bs  =  \x -> fromMaybe undefined $ lookup x bs---mkFun2 :: (Eq a, Eq b) => [((a,b),c)] -> a -> b -> c-mkFun2 bs  =  \x y -> fromMaybe undefined $ lookup (x,y) bs---mkFun3 :: (Eq a, Eq b, Eq c) => [((a,b,c),d)] -> a -> b -> c -> d-mkFun3 bs  =  \x y z -> fromMaybe undefined $ lookup (x,y,z) bs
src/Conjure/Utils.hs view
@@ -4,7 +4,7 @@ -- License     : 3-Clause BSD  (see the file LICENSE) -- Maintainer  : Rudy Matela <rudy@matela.com.br> ----- An internal module of 'Conjure'.+-- An internal module of "Conjure". -- This exports 'Data.List', 'Data.Maybe', 'Data.Function' -- and a few other simple utitilites. {-# LANGUAGE CPP #-}@@ -19,17 +19,11 @@   , count   , nubOn   , nubSort-  , iterateUntil   , mzip   , groupOn #if __GLASGOW_HASKELL__ < 710   , sortOn #endif-  , takeUntil-  , takeNextWhile-  , takeNextUntil-  , deconstructions-  , isDeconstruction   , idIO   , mapHead   , sets@@ -37,7 +31,6 @@   , allEqual   , choices   , choicesThat-  , filterAnd   ) where @@ -50,18 +43,22 @@  import System.IO.Unsafe +-- | Checks if all elements of a list are equal. allEqual :: Eq a => [a] -> Bool allEqual []  =  False allEqual [x]  =  False allEqual [x,y]  =  x == y allEqual (x:y:xs)  =  x == y && allEqual (y:xs) +-- | Counts the number of occurrences on a list. count :: (a -> Bool) -> [a] -> Int count p  =  length . filter p +-- | Nubs using a given field. nubOn :: Eq b => (a -> b) -> [a] -> [a] nubOn f  =  nubBy ((==) `on` f) +-- | Equivalent to @nub . sort@ but running in /O(n log n)/. nubSort :: Ord a => [a] -> [a] nubSort  =  nnub . sort   where@@ -70,55 +67,26 @@   nnub [x] = [x]   nnub (x:xs) = x : nnub (dropWhile (==x) xs) -iterateUntil :: (a -> a -> Bool) -> (a -> a) -> a -> a-iterateUntil (?) f  =  iu-  where-  iu x | x ? fx     =  x-       | otherwise  =  iu fx-    where-    fx  =  f x-+-- | Zips 'Monoid' values leaving trailing values.+--+-- > > mzip ["ab","cd"] ["ef"]+-- > ["abef","cd"] mzip :: Monoid a => [a] -> [a] -> [a] mzip [] []  =  [] mzip [] ys  =  ys mzip xs []  =  xs mzip (x:xs) (y:ys)  =  x <> y : mzip xs ys +-- | Group values using a given field selector. groupOn :: Eq b => (a -> b) -> [a] -> [[a]] groupOn f = groupBy ((==) `on` f)  #if __GLASGOW_HASKELL__ < 710+-- | 'sort' on a given field. sortOn :: Ord b => (a -> b) -> [a] -> [a] sortOn f = sortBy (compare `on` f) #endif -takeUntil :: (a -> Bool) -> [a] -> [a]-takeUntil p  =  takeWhile (not . p)--takeNextWhile :: (a -> a -> Bool) -> [a] -> [a]-takeNextWhile (?)  =  t-  where-  t (x:y:xs) | x ? y  =  x : t (y:xs)-             | otherwise  =  [x]-  t xs  =  xs--takeNextUntil :: (a -> a -> Bool) -> [a] -> [a]-takeNextUntil (?)  =  takeNextWhile (not .: (?))-  where-  (.:)  =  (.) . (.)--deconstructions :: (a -> Bool) -> (a -> a) -> a -> [a]-deconstructions z d x  =  takeUntil z-                       $  iterate d x---- | The deconstruction is considered valid if it converges---   for more than half of the given values.-isDeconstruction :: [a] -> (a -> Bool) -> (a -> a) -> Bool-isDeconstruction xs z d  =  count is xs >= l `div` 2-  where-  is x  =  length (take l $ deconstructions z d x) < l-  l  =  length xs- -- | __WARNING:__ --   uses 'unsafePerformIO' and should only be used for debugging! --@@ -130,31 +98,31 @@   action x   return x +-- | Applies a function to the head of a list. mapHead :: (a -> a) -> [a] -> [a] mapHead f (x:xs)  =  f x : xs +-- | Return sets of values based on the list.+--+-- The values in the list must me unique. sets :: [a] -> [[a]] sets []  =  [[]] sets (x:xs)  =  map (x:) ss ++ ss   where   ss  =  sets xs +-- | Like 'head' but allows providing a default value. headOr :: a -> [a] -> a headOr x []  =  x headOr _ (x:xs)  =  x +-- | Lists choices of values. choices :: [a] -> [(a,[a])] choices []  =  [] choices (x:xs)  =  (x,xs) : map (mapSnd (x:)) (choices xs)   where   mapSnd f (x,y)  =  (x,f y) +-- | Lists choices of values that follow a property. choicesThat :: (a -> [a] -> Bool) -> [a] -> [(a,[a])] choicesThat (?)  =  filter (uncurry (?)) . choices--filterAnd :: (a -> Bool) -> [a] -> ([a],Bool)-filterAnd p xs  =  (xs', and ps)-  where-  xps  =  [(x,p x) | x <- xs]-  xs'  =  [x | (x,True) <- xps]-  ps   =  [p | (_,p) <- xps]
stack.yaml view
@@ -11,4 +11,4 @@ extra-deps: - leancheck-0.9.10 - speculate-0.4.14-- express-1.0.6+- express-1.0.8
test/Test.hs view
@@ -13,7 +13,6 @@   , module Test.LeanCheck   , module Test.LeanCheck.Utils   , module Test.ListableExpr-  , module Test.Candidates    , mainTest   )@@ -25,7 +24,6 @@ import Test.LeanCheck import Test.LeanCheck.Utils import Test.ListableExpr-import Test.Candidates  import Conjure import Conjure.Expr hiding (delete, insert)
− test/Test/Candidates.hs
@@ -1,60 +0,0 @@--- |--- Module      : TEst.Candidates--- Copyright   : (c) 2021 Rudy Matela--- License     : 3-Clause BSD  (see the file LICENSE)--- Maintainer  : Rudy Matela <rudy@matela.com.br>------ Reference implementations of candidate generation.------ Bottom-up and top-down-module Test.Candidates-  ( boupCandidates-  , townCandidates-  , dropTrail-  )-where--import Conjure.Expr-import Test.LeanCheck--boupCandidates :: Expr -> [Expr] -> [[Expr]]-boupCandidates appn primitives  =  dropTrail $ filterT (\e -> typ e == typ appn) boup-  where-  boup :: [[Expr]]-  boup = expressionsT [primitives]--  expressionsT ds  =  ds \/ (delay $ productMaybeWith ($$) es es)-    where-    es = expressionsT ds--townCandidates :: Expr -> [Expr] -> [[Expr]]-townCandidates appn primitives  =  normalizeT-                                $  filterT (not . hasHole)-                                $  town [[holeAsTypeOf appn]]-  where-  town :: [[Expr]] -> [[Expr]]-  town ((e:es):ess)  =  [[e]] \/ town (expand e \/ (es:ess))-  town ([]:ess)  =  []:town ess-  town []  =  []--  expand :: Expr -> [[Expr]]-  expand e  =  case holesBFS e of-    [] -> []-    (h:_) -> mapT (fillBFS e) (replacementsFor h)--  replacementsFor :: Expr -> [[Expr]]-  replacementsFor h  =  filterT (\e -> typ e == typ h)-                     $  primitiveApplications primitives---- like normalizeT, but considers 6 empty tiers as an infinite trail of tiers--- this should only be used on testing-dropTrail :: [[a]] -> [[a]]-dropTrail []  =  []-dropTrail [[]]  =  []-dropTrail [[],[]]  =  []-dropTrail [[],[],[]]  =  []-dropTrail [[],[],[],[]]  =  []-dropTrail [[],[],[],[],[]]  =  []-dropTrail [[],[],[],[],[],[]]  =  []-dropTrail ([]:[]:[]:[]:[]:[]:_)  =   []-dropTrail (xs:xss)  =  xs:dropTrail xss
+ test/derive.hs view
@@ -0,0 +1,91 @@+-- Copyright (c) 2019-2021 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable #-}++import Test hiding ((-:), (->:))+-- -: and ->: should be generated by deriveConjurable++data Choice  =  Ae | Bee | Cee deriving (Show, Eq, Typeable)+data Peano  =  Zero | Succ Peano deriving (Show, Eq, Typeable)+data List a  =  a :- List a | Nil deriving (Show, Eq, Typeable)+data Bush a  =  Bush a :-: Bush a | Leaf a deriving (Show, Eq, Typeable)+data Tree a  =  Node (Tree a) a (Tree a) | Null deriving (Show, Eq, Typeable)++deriveConjurable ''Choice+deriveConjurable ''Peano+deriveConjurable ''List+deriveConjurable ''Bush+deriveConjurable ''Tree++-- Nested datatype cascade+data Nested  =  Nested N0 (N1 Int) (N2 Int Int) deriving (Eq, Show, Typeable)+data N0      =  R0 Int deriving (Eq, Show, Typeable)+data N1 a    =  R1 a   deriving (Eq, Show, Typeable)+data N2 a b  =  R2 a b deriving (Eq, Show, Typeable)++deriveConjurableCascading ''Nested++-- Recursive nested datatype cascade+data RN       =  RN RN0 (RN1 Int) (RN2 Int RN) deriving (Eq, Show, Typeable)+data RN0      =  Nest0 Int | Recurse0 RN deriving (Eq, Show, Typeable)+data RN1 a    =  Nest1 a   | Recurse1 RN deriving (Eq, Show, Typeable)+data RN2 a b  =  Nest2 a b | Recurse2 RN deriving (Eq, Show, Typeable)+-- beware: values of the above type are always infinite!+--         derivation works but full evaluation does not terminate++deriveConjurableCascading ''RN++-- Those should have no effect (instance already exists):+{- uncommenting those should generate warnings+deriveConjurable ''Bool+deriveConjurable ''Maybe+deriveConjurable ''Either+-}++-- Those should not generate warnings+deriveConjurableIfNeeded ''Bool+deriveConjurableIfNeeded ''Maybe+deriveConjurableIfNeeded ''Either++data Mutual    =  Mutual0   | Mutual CoMutual deriving (Eq, Show, Typeable)+data CoMutual  =  CoMutual0 | CoMutual Mutual deriving (Eq, Show, Typeable)++deriveConjurableCascading ''Mutual+++main :: IO ()+main  =  mainTest tests 5040++tests :: Int -> [Bool]+tests n  =+  [ True++  , conjurableOK (undefined :: Bool)+  , conjurableOK (undefined :: Int)+  , conjurableOK (undefined :: Char)+  , conjurableOK (undefined :: [Bool])+  , conjurableOK (undefined :: [Int])+  , conjurableOK (undefined :: String)++  , conjurableOK (undefined :: Choice)+  , conjurableOK (undefined :: Peano)+  , conjurableOK (undefined :: List Int)+  , conjurableOK (undefined :: Bush Int)+  , conjurableOK (undefined :: Tree Int)+--, conjurableOK (undefined :: RN) -- TODO: FIX: infinite loop somewhere...+  ]+++-- checks if the functions conjureEquality, conjureExpress and conjureTiers+-- were correctly generated.+conjurableOK :: (Eq a, Show a, Express a, Listable a, Conjurable a) => a -> Bool+conjurableOK x  =  and+  [ holds 60 $ (-==-) ==== (==)+  , holds 60 $ expr' === expr+  , tiers =| 6 |= (tiers -: [[x]])+  ]+  where+  (-==-)  =  evl (fromJust $ conjureEquality x) -:> x+  tiers'  =  mapT evl (fromJust $ conjureTiers x) -: [[x]]+  expr'  =  (conjureExpress x . val) -:> x
test/expr.hs view
@@ -67,67 +67,6 @@        , one -*- one        ] -  , primitiveHoles [false, true]  ==  [b_]-  , primitiveHoles [zero, one]  ==  [i_]-  , primitiveHoles [false, zero]  ==  [b_, i_]--  , primitiveHoles [false, true, notE]  ==-      [ hole (undefined :: Bool)-      , hole (undefined :: Bool -> Bool)-      ]--  , primitiveHoles [false, true, notE, andE, orE]  ==-      [ hole (undefined :: Bool)-      , hole (undefined :: Bool -> Bool)-      , hole (undefined :: Bool -> Bool -> Bool)-      ]--  , primitiveHoles [false, true, andE, orE]  ==-      [ hole (undefined :: Bool)-      , hole (undefined :: Bool -> Bool)-      , hole (undefined :: Bool -> Bool -> Bool)-      ]--  , primitiveHoles [zero, one, plus, times]  ==-      [ hole (undefined :: Int)-      , hole (undefined :: Int -> Int)-      , hole (undefined :: Int -> Int -> Int)-      ]--  , primitiveHoles [false, true, andE, orE, zero, one, plus, times]-    == [ hole (undefined :: Bool)-       , hole (undefined :: Int)-       , hole (undefined :: Bool -> Bool)-       , hole (undefined :: Int -> Int)-       , hole (undefined :: Bool -> Bool -> Bool)-       , hole (undefined :: Int -> Int -> Int)-       ]--  , holds n $ \es -> all (`elem` primitiveHoles es) (map holeAsTypeOf es)-  , fails n $ \es -> primitiveHoles es == map holeAsTypeOf es--  , map (map show) (primitiveApplications [false, true, andE, orE, zero, one, plus, times])-    == [ [ "False :: Bool"-         , "True :: Bool"-         , "(&&) :: Bool -> Bool -> Bool"-         , "(||) :: Bool -> Bool -> Bool"-         , "0 :: Int"-         , "1 :: Int"-         , "(+) :: Int -> Int -> Int"-         , "(*) :: Int -> Int -> Int"-         ]-       , [ "(_ &&) :: Bool -> Bool"-         , "(_ ||) :: Bool -> Bool"-         , "(_ +) :: Int -> Int"-         , "(_ *) :: Int -> Int"-         ]-       , [ "_ && _ :: Bool"-         , "_ || _ :: Bool"-         , "_ + _ :: Int"-         , "_ * _ :: Int"-         ]-       ]-   , holds n $ \e -> sort (valuesBFS e) == sort (values e)   , holds n $ \e -> holesBFS e == filter isHole (valuesBFS e)   , valuesBFS false == [false]@@ -154,12 +93,6 @@                                     in e3 == e1                                     || length (holes e3) == length (holes e1) - 1 + length (holes e2) -  , boupCandidates i_ [zero, one, plus] =$ map sort . take 12 $=-    townCandidates i_ [zero, one, plus]--  , holds n $ \e es -> not (any hasHole es)-                   ==> boupCandidates e es =$ map sort . take 12 $= townCandidates e es-   , possibleHoles [plus, times, zero, one]     == [ hole (undefined :: Int)        , hole (undefined :: Int -> Int)@@ -226,4 +159,19 @@          , (yy-:-yys, yy-:-xxs)          ]        ]++  -- type-correct applications are allowed on $$, $$|< and $$**+  , absE $$   zero  ==  Just (abs' zero)+  , absE $$|< zero  ==  Just (abs' zero)+  , absE $$** zero  ==  Just (abs' zero)++  -- kind-correct applications are allowed on $$|< and $$**+  , ordE $$   zero  ==  Nothing+  , ordE $$|< zero  ==  Just (ordE :$ zero)+  , ordE $$** zero  ==  Just (ordE :$ zero)++  -- type-incorrect applications are allowed on $$**+  , zero $$   zero  ==  Nothing+  , zero $$|< zero  ==  Nothing+  , zero $$** zero  ==  Just (zero :$ zero)   ]
test/utils.hs view
@@ -10,48 +10,12 @@ tests n  =   [ True -  , holds n $ \x -> iterateUntil (==) (`quot` (2 :: Int)) x == 0-  , holds n $ \xs -> iterateUntil (==) (drop 1) xs == ([]::[Bool])-   , holds n $ \xs ys -> length xs == length ys                     ==> zipWith (<>) xs ys == mzip xs (ys :: [[Int]])    , holds n $ \xs ys -> length xs >= length ys                     ==> zipWith (<>) xs (ys <> repeat mempty) == mzip xs (ys :: [[Int]]) -  , takeUntil (== 5) [1..] == [1,2,3,4]-  , takeUntil (> 4)  [1..] == [1,2,3,4]--  , takeNextWhile (<) []  ==  ([]::[Int])-  , takeNextWhile (<) [0]  ==  [0]-  , takeNextWhile (<) [0,1]  ==  [0,1]-  , takeNextWhile (<) [0,1,2]  ==  [0,1,2]-  , takeNextWhile (<) [0,1,2,1,0]  ==  [0,1,2]-  , takeNextWhile (/=) [3,2,1,0,0,0] == [3,2,1,0]-  , takeNextUntil (==) [3,2,1,0,0,0] == [3,2,1,0]-  , takeNextUntil (>) [0,1,2,1,0] == [0,1,2]--  , deconstructions null tail [1,2,3 :: Int]-    == [ [1,2,3]-       , [2,3]-       , [3]-       ]-  , deconstructions null tail ([] :: [Int]) == []-  , deconstructions (==0) (`div`2) 15-    == [15, 7, 3, 1]--  ,       isDec m (null :: [A] -> Bool) tail-  , not $ isDec m (null :: [A] -> Bool) id-  ,       isDec m (null :: [A] -> Bool) (drop 1)-  ,       isDec m (null :: [A] -> Bool) (drop 2)-  ,       isDec m (null :: [A] -> Bool) (drop 3)-  ,       isDec m (<0) (\x -> x-1 :: Int)-  ,       isDec m (<0) (\x -> x-2 :: Int)-  ,       isDec m (==0) (\x -> x-1 :: Int)-  , not $ isDec m (==0) (\x -> x-2 :: Int)-  ,       isDec m (==0) (\x -> x `div` 2 :: Int)-  ,       isDec m (==0) (\x -> x `quot` 2 :: Int)-   , sets []  ==  [[] :: [Int]]   , sets [1]  ==  [[1], [] :: [Int]]   , sets [1,2]  ==  [[1,2], [1], [2], [] :: [Int]]@@ -59,13 +23,3 @@   ]   where   m  =  n `div` 60----- Checks if the given pair of functions are a valid deconstruction--- for Listable values.--- The deconstruction is considered valid if it converges--- for more than 50% of values.-isDec :: Listable a-      => Int-      -> (a -> Bool) -> (a -> a) -> Bool-isDec m  =  isDeconstruction (take m list)