packages feed

code-conjure 0.2.4 → 0.2.6

raw patch · 26 files changed

+909/−202 lines, 26 filesdep ~expressdep ~leancheckdep ~speculatePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: express, leancheck, speculate

API changes (from Hackage documentation)

+ Conjure.Engine: appendInt :: Expr
+ Conjure.Engine: encompasses :: Expr -> Expr -> Bool
+ Conjure.Engine: groundBinds :: (Expr -> [[Expr]]) -> Expr -> [Binds]
+ Conjure.Engine: hasHole :: Expr -> Bool
+ Conjure.Engine: isComplete :: Expr -> Bool
+ Conjure.Engine: isRootNormalE :: Thy -> Expr -> Bool
+ Conjure.Engine: theoryFromAtoms :: (Expr -> Expr -> Bool) -> Int -> [[Expr]] -> Thy
+ Conjure.Expr: ($$**) :: Expr -> Expr -> Maybe Expr
+ Conjure.Expr: ($$|<) :: Expr -> Expr -> Maybe Expr
+ Conjure.Expr: (>$$<) :: [Expr] -> [Expr] -> [Expr]
+ Conjure.Expr: appendInt :: Expr
+ Conjure.Expr: encompasses :: Expr -> Expr -> Bool
+ Conjure.Expr: fillBFS :: Expr -> Expr -> Expr
+ Conjure.Expr: hasHole :: Expr -> Bool
+ Conjure.Expr: holesBFS :: Expr -> [Expr]
+ Conjure.Expr: isComplete :: 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.Expr: valuesBFS :: Expr -> [Expr]
+ Conjure.Utils: iterateUntil :: (a -> a -> Bool) -> (a -> a) -> a -> a
+ Conjure.Utils: mzip :: Monoid a => [a] -> [a] -> [a]
- Conjure: conjure1 :: (Eq a, Show a, Conjurable a, Conjurable b) => String -> Spec1 a b -> [Expr] -> IO ()
+ Conjure: conjure1 :: (Eq a, Eq b, Show a, Conjurable a, Conjurable b) => String -> Spec1 a b -> [Expr] -> IO ()
- Conjure: conjure1With :: (Eq a, Show a, Conjurable a, Conjurable b) => Args -> String -> Spec1 a b -> [Expr] -> IO ()
+ Conjure: conjure1With :: (Eq a, Eq b, Show a, Conjurable a, Conjurable b) => Args -> String -> Spec1 a b -> [Expr] -> IO ()
- Conjure: conjure2 :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c) => String -> Spec2 a b c -> [Expr] -> IO ()
+ Conjure: conjure2 :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c) => String -> Spec2 a b c -> [Expr] -> IO ()
- Conjure: conjure2With :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c) => Args -> String -> Spec2 a b c -> [Expr] -> IO ()
+ Conjure: conjure2With :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c) => Args -> String -> Spec2 a b c -> [Expr] -> IO ()
- Conjure: conjure3 :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c, Show c, Conjurable d) => String -> Spec3 a b c d -> [Expr] -> IO ()
+ Conjure: conjure3 :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c, Show c, Conjurable d, Eq d) => String -> Spec3 a b c d -> [Expr] -> IO ()
- Conjure: conjure3With :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c, Show c, Conjurable d) => Args -> String -> Spec3 a b c d -> [Expr] -> IO ()
+ Conjure: conjure3With :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c, Show c, Conjurable d, Eq d) => Args -> String -> Spec3 a b c d -> [Expr] -> IO ()
- Conjure.Engine: class Typeable a => Express a
+ Conjure.Engine: class (Show a, Typeable a) => Express a
- Conjure.Expr: class Typeable a => Express a
+ Conjure.Expr: class (Show a, Typeable a) => Express a
- Conjure.Spec: conjure1 :: (Eq a, Show a, Conjurable a, Conjurable b) => String -> Spec1 a b -> [Expr] -> IO ()
+ Conjure.Spec: conjure1 :: (Eq a, Eq b, Show a, Conjurable a, Conjurable b) => String -> Spec1 a b -> [Expr] -> IO ()
- Conjure.Spec: conjure1With :: (Eq a, Show a, Conjurable a, Conjurable b) => Args -> String -> Spec1 a b -> [Expr] -> IO ()
+ Conjure.Spec: conjure1With :: (Eq a, Eq b, Show a, Conjurable a, Conjurable b) => Args -> String -> Spec1 a b -> [Expr] -> IO ()
- Conjure.Spec: conjure2 :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c) => String -> Spec2 a b c -> [Expr] -> IO ()
+ Conjure.Spec: conjure2 :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c) => String -> Spec2 a b c -> [Expr] -> IO ()
- Conjure.Spec: conjure2With :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c) => Args -> String -> Spec2 a b c -> [Expr] -> IO ()
+ Conjure.Spec: conjure2With :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c) => Args -> String -> Spec2 a b c -> [Expr] -> IO ()
- Conjure.Spec: conjure3 :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c, Show c, Conjurable d) => String -> Spec3 a b c d -> [Expr] -> IO ()
+ Conjure.Spec: conjure3 :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c, Show c, Conjurable d, Eq d) => String -> Spec3 a b c d -> [Expr] -> IO ()
- Conjure.Spec: conjure3With :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c, Show c, Conjurable d) => Args -> String -> Spec3 a b c d -> [Expr] -> IO ()
+ Conjure.Spec: conjure3With :: (Conjurable a, Eq a, Show a, Conjurable b, Eq b, Show b, Conjurable c, Eq c, Show c, Conjurable d, Eq d) => Args -> String -> Spec3 a b c d -> [Expr] -> IO ()

Files

.gitignore view
@@ -39,3 +39,4 @@ proto/u-conjure test/expr test/conjurable+test/utils
Makefile view
@@ -19,7 +19,8 @@  TESTS = \   test/expr \-  test/conjurable+  test/conjurable \+  test/utils  all: mk/toplibs 
TODO.md view
@@ -4,18 +4,36 @@ A non-exhaustive list of things TO DO for Conjure.  +* top-down generation of candidate expressions++* generate functions with top-level case patterns:++        len []  =  0+        len (x:xs)  =  1 + len xs++* only allow recursion on deconstructed arguments:++        foo (x:xs)  =  ... len xs ...++  this will require generation of functions with top-level case patterns.++ ### for later -* allow conjuring from tests instead of partial definitions?+* exclude magic numbers?  e.g.: `1+1`?  * allow conjuring from partially defined implementations? -    partial :: ((Int -> Int) -> Int -> Int) -> (Int -> Int)-    partial impl  =  f-      where-      f n  =  if n == 0-              then 1-              else impl f n+        partial :: ((Int -> Int) -> Int -> Int) -> (Int -> Int)+        partial impl  =  f+          where+          f n  =  if n == 0+                  then 1+                  else impl f n++* consider leveraging lazyness somehow?++* consider leveraging polymorphism somehow?   This file is part of Conjure,
bench/runtime/zero/bench/ill-hit.runtime view
@@ -1,1 +1,1 @@-2.26+1.89
bench/runtime/zero/eg/bools.runtime view
@@ -1,1 +1,1 @@-7.78+7.20
bench/runtime/zero/eg/factorial.runtime view
@@ -1,1 +1,1 @@-6.99+7.18
bench/runtime/zero/eg/ints.runtime view
@@ -1,1 +1,1 @@-1.83+1.84
bench/runtime/zero/eg/list.runtime view
@@ -1,1 +1,1 @@-10.71+10.23
bench/runtime/zero/eg/spec.runtime view
@@ -1,1 +1,1 @@-1.63+1.47
bench/runtime/zero/eg/tapps.runtime view
@@ -1,1 +1,1 @@-0.96+0.87
bench/runtime/zero/proto/u-conjure.runtime view
@@ -1,1 +1,1 @@-0.10+0.32
bench/runtime/zero/versions view
@@ -1,4 +1,4 @@ GHC 8.10.4 leancheck-0.9.4-express-0.1.8+express-0.1.10 speculate-0.4.6
changelog.md view
@@ -2,6 +2,14 @@ ============================  +v0.2.6+------++* require Express v0.1.10 due to `hasHole` being now exported there+* require Eq result on `conjure1`, `conjure2` and `conjure3`+* code cleanup and more tests++ v0.2.4 ------ 
code-conjure.cabal view
@@ -3,7 +3,7 @@ -- Copyright (C) 2021 Rudy Matela -- Distributed under the 3-Clause BSD licence (see the file LICENSE). name:                code-conjure-version:             0.2.4+version:             0.2.6 synopsis:            conjure Haskell functions out of partial definitions description:   Conjure is a tool that produces Haskell functions out of partial definitions.@@ -65,7 +65,7 @@ source-repository this   type:            git   location:        https://github.com/rudymatela/conjure-  tag:             v0.2.4+  tag:             v0.2.6  library   exposed-modules: Conjure@@ -79,14 +79,14 @@                , leancheck >= 0.9.4                , template-haskell                , speculate >= 0.4.6-               , express >= 0.1.8+               , express >= 0.1.10   hs-source-dirs:      src   default-language:    Haskell2010  test-suite expr   type:                exitcode-stdio-1.0   main-is:             expr.hs-  other-modules:       Test+  other-modules:       Test, Test.ListableExpr, Test.Candidates   hs-source-dirs:      test   build-depends:       base >= 4 && < 5, leancheck, express, speculate, code-conjure   default-language:    Haskell2010@@ -94,7 +94,15 @@ test-suite conjurable   type:                exitcode-stdio-1.0   main-is:             conjurable.hs-  other-modules:       Test+  other-modules:       Test, Test.ListableExpr, Test.Candidates+  hs-source-dirs:      test+  build-depends:       base >= 4 && < 5, leancheck, express, speculate, code-conjure+  default-language:    Haskell2010++test-suite utils+  type:                exitcode-stdio-1.0+  main-is:             utils.hs+  other-modules:       Test, Test.ListableExpr, Test.Candidates   hs-source-dirs:      test   build-depends:       base >= 4 && < 5, leancheck, express, speculate, code-conjure   default-language:    Haskell2010
mk/depend.mk view
@@ -147,6 +147,8 @@   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 \@@ -156,10 +158,14 @@   src/Conjure/Conjurable.hs test/conjurable: \   test/Test.hs \+  test/Test/ListableExpr.hs \+  test/Test/Candidates.hs \   test/conjurable.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 \@@ -169,10 +175,20 @@   src/Conjure/Conjurable.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.hs \@@ -181,4 +197,23 @@   src/Conjure/Conjurable.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.hs \+  src/Conjure/Expr.hs \+  src/Conjure/Engine.hs \+  src/Conjure/Conjurable.hs+test/utils: \+  test/utils.hs \+  test/Test.hs \+  test/Test/ListableExpr.hs \+  test/Test/Candidates.hs \   mk/toplibs
proto/u-conjure.hs view
@@ -20,8 +20,10 @@ import Data.List import Data.Maybe import Data.Express+import Data.Typeable import Test.LeanCheck.Error + square :: Int -> Int square 0  =  0 square 1  =  1@@ -35,37 +37,64 @@ add 1 0  =  1 add 1 1  =  2 -fact :: Int -> Int-fact 0  =  1-fact 1  =  1-fact 2  =  2-fact 3  =  6-fact 4  =  24+factorial :: Int -> Int+factorial 0  =  1+factorial 1  =  1+factorial 2  =  2+factorial 3  =  6+factorial 4  =  24  second :: [Int] -> Int second [x,y]  =  y second [x,y,z]  =  y second [x,y,z,w]  =  y +-- reverse+reverse' :: [Int] -> [Int]+reverse' [x,y]  =  [y,x]+reverse' [x,y,z]  =  [z,y,x]++-- +++(+++) :: [Int] -> [Int] -> [Int]+[x] +++ [y]  =  [x,y]+[x,y] +++ [z,w]  =  [x,y,z,w]++ main :: IO () main  =  do-  value "square" (square :: Int -> Int) `conjureFrom` intBackground-  value "add" (add :: Int -> Int -> Int) `conjureFrom` intBackground-  value "fact" (fact :: Int -> Int) `conjureFrom` intBackground+  conjure "square"    square    primitives+  conjure "add"       add       primitives+  conjure "factorial" factorial primitives -  value "==>" (==>) `conjureFrom`-    [ val False-    , val True-    , value "not" not-    , value "&&" (&&)-    , value "||" (||)+  conjure "factorial"   factorial+    [ val (0 :: Int)+    , val (1 :: Int)+    , value "+" ((+) :: Int -> Int -> Int)+    , value "*" ((*) :: Int -> Int -> Int)+    , value "foldr" (foldr :: (Int -> Int -> Int) -> Int -> [Int] -> Int)+    , value "enumFromTo" (enumFromTo :: Int -> Int -> [Int])     ] -  value "second" (second :: [Int] -> Int) `conjureFrom` listBackground-  value "reverse" (reverse :: [Int] -> [Int]) `conjureFrom` listBackground+  conjure "second"  second   listPrimitives+  conjure "++"      (+++)    listPrimitives+  conjure "reverse" reverse' listPrimitives++  -- even by using fold and some cheating,+  -- this function is out of reach+  --  reverse xs  =  foldr (\x xs -> xs ++ [x]) [] xs+  --  reverse xs  =  foldr (flip (++) . unit) [] xs+  conjure "reverse" reverse' $ listPrimitives +++    [ value "unit" ((:[]) :: Int -> [Int])+    , value "++" ((++) :: [Int] -> [Int] -> [Int])+    -- these last two are cheats:+    , value "flip" (flip :: ([Int]->[Int]->[Int]) -> [Int] -> [Int] -> [Int])+    , value "." ((.) :: ([Int]->[Int]->[Int]) -> (Int->[Int]) -> Int -> [Int] -> [Int])+    ]+   where-  intBackground :: [Expr]-  intBackground  =++  primitives :: [Expr]+  primitives =     [ val (0 :: Int)     , val (1 :: Int)     , val (2 :: Int)@@ -74,67 +103,65 @@     , value "*" ((*) :: Int -> Int -> Int)     , value "-" ((-) :: Int -> Int -> Int)     ]-  listBackground :: [Expr]-  listBackground  =++  listPrimitives :: [Expr]+  listPrimitives =     [ val (0 :: Int)     , val (1 :: Int)     , val ([] :: [Int])     , value "head" (head :: [Int] -> Int)     , value "tail" (tail :: [Int] -> [Int])     , value ":" ((:) :: Int -> [Int] -> [Int])-    , value "++" ((++) :: [Int] -> [Int] -> [Int])+    , value "foldr" (foldr :: (Int -> [Int] -> [Int]) -> [Int] -> [Int] -> [Int])     ]  -conjureFrom :: Expr -> [Expr] -> IO ()-ff `conjureFrom` es  =  do-  print ff  -- prints the type signature-  case rs of+conjure :: Typeable f => String -> f -> [Expr] -> IO ()+conjure nm f primitives  =  do+  print (value nm f) -- prints the type signature+  case conjureImplementations nm f primitives of     []    -> putStrLn $ "cannot conjure" --  es    -> putStrLn $ unlines $ map showEq es  -- uncomment to show all found variations     (e:_) -> putStrLn $ showEq e   putStrLn ""   where-  nm (Value s _)  =  s-  rrff  =  ('_':nm ff) `varAsTypeOf` ff-  rs  =  [ ffxx -==- e-         | e <- candidateExprsFrom $ [rrff] ++ xxs ++ filter isGround es-         , isWellTyped (ffxx -==- e)-         , isTrue (ffxx -==- e)-         , isDefined e-         ]-  ffxx  =  mostGeneralCanonicalVariation-        .  fromJust-        $  application ff es-  (_:xxs)  =  unfoldApp ffxx   showEq eq  =  showExpr (lhs eq) ++ "  =  " ++ showExpr (rhs eq)  -application :: Expr -> [Expr] -> Maybe Expr-application ff es  =  appn ff+conjureImplementations :: Typeable f => String -> f -> [Expr] -> [Expr]+conjureImplementations nm f primitives  =+  [ appn -==- e+  | e <- candidateExprsFrom $ exs ++ primitives+  , isTrue (appn -==- e)+  ]   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+  appn  =  application nm f primitives+  (ef:exs)  =  unfoldApp appn+  isTrue e  =  all (errorToFalse . eval False) . map (e //-) $ definedBinds appn  -candidateExprsFrom :: [Expr] -> [Expr]-candidateExprsFrom  =  concat . take 6 . expressionsT+definedBinds :: Expr -> [[(Expr,Expr)]]+definedBinds ffxx  =  [bs | bs <- bss, errorToFalse . eval False $ e //- bs]   where-  expressionsT ds  =  [ds] \/ (delay $ productMaybeWith ($$) es es)-    where-    es = expressionsT ds+  e  =  ffxx -==- ffxx+  bss  =  take 360 $ groundBinds ffxx  -isTrue :: Expr -> Bool-isTrue  =  all (errorToTrue . eval False) . take 60 . grounds+application :: Typeable f => String -> f -> [Expr] -> Expr+application nm f es  =  mostGeneralCanonicalVariation $ appn (value nm f)+  where+  appn ff | isFun ff   =  case [e | Just (_ :$ e) <- (map (ff $$)) es] of+                          [] -> error "application: could not find type representative"+                          (e:_) -> appn (ff :$ holeAsTypeOf e)+          | otherwise  =  ff  --- checks if a function is defined for at least one combination of argument values-isDefined :: Expr -> Bool-isDefined e  =  any (isJust . errorToNothing . eval False) . take 60 . grounds $ (e -==- e)+candidateExprsFrom :: [Expr] -> [Expr]+candidateExprsFrom  =  concat . take 7 . expressionsT+  where+  expressionsT ds  =  [ds] \/ (delay $ productMaybeWith ($$) es es)+    where+    es = expressionsT ds   (-==-) :: Expr -> Expr -> Expr@@ -148,14 +175,14 @@   headOr x []     =  x   headOr _ (x:_)  =  x + lhs, rhs :: Expr -> Expr lhs (((Value "==" _) :$ e) :$ _)  =  e rhs (((Value "==" _) :$ _) :$ e)  =  e  -grounds :: Expr -> [Expr]-grounds e  =  map (e //-)  .  concat-           $  products [mapT ((,) v) (tiersFor v) | v <- nubVars e]+groundBinds :: Expr -> [[(Expr,Expr)]]+groundBinds e  =  concat $ products [mapT ((,) v) (tiersFor v) | v <- nubVars e]   tiersFor :: Expr -> [[Expr]]
src/Conjure/Engine.hs view
@@ -10,35 +10,82 @@ -- (a.k.a.: functional inductive programming) {-# LANGUAGE CPP, RecordWildCards, TupleSections #-} module Conjure.Engine-  ( module Data.Express-  , module Data.Express.Fixtures-  , module Test.Speculate.Engine-  , module Test.Speculate.Reason+  ( conjure+  , conjureWithMaxSize   , Args(..)   , args-  , conjure   , conjureWith-  , conjureWithMaxSize   , conjpure   , conjpureWith   , candidateExprs+  , module Data.Express+  , module Data.Express.Fixtures+  , module Test.Speculate.Engine+  , module Test.Speculate.Reason   ) where  import Data.Express import Data.Express.Fixtures hiding ((-==-))-import qualified Data.Ratio-import Test.LeanCheck.Error (errorToTrue, errorToFalse, errorToNothing)++import Test.LeanCheck import Test.LeanCheck.Tiers-import Test.Speculate hiding ((===), Args(..), args)-import Test.Speculate.Reason-import Test.Speculate.Engine-import Test.Speculate.Expr-import System.IO+import Test.LeanCheck.Error (errorToTrue, errorToFalse, errorToNothing) +import Test.Speculate.Reason (isRootNormalE)+import Test.Speculate.Engine (theoryFromAtoms, groundBinds)+ import Conjure.Expr import Conjure.Conjurable ++-- | Conjures an implementation of a partially defined function.+--+-- Takes a 'String' with the name of a function,+-- a partially-defined function from a conjurable type,+-- and a list of building blocks encoded as 'Expr's.+--+-- For example, given:+--+-- > square :: Int -> Int+-- > square 0  =  0+-- > square 1  =  1+-- > square 2  =  4+-- >+-- > primitives :: [Expr]+-- > primitives =+-- >   [ val (0::Int)+-- >   , val (1::Int)+-- >   , value "+" ((+) :: Int -> Int -> Int)+-- >   , value "*" ((*) :: Int -> Int -> Int)+-- > ]+--+-- The conjure function does the following:+--+-- > > conjure "square" square primitives+-- > square :: Int -> Int+-- > -- testing 3 combinations of argument values+-- > -- looking through 3 candidates of size 1+-- > -- looking through 3 candidates of size 2+-- > -- looking through 5 candidates of size 3+-- > square x  =  x * x+--+-- The primitives list is defined with 'val' and 'value'.+conjure :: Conjurable f => String -> f -> [Expr] -> IO ()+conjure  =  conjureWith args+++-- | Like 'conjure' but allows setting the maximum size of considered expressions+--   instead of the default value of 12.+--+-- > conjureWithMaxSize 10 "function" function [...]+conjureWithMaxSize :: Conjurable f => Int -> String -> f -> [Expr] -> IO ()+conjureWithMaxSize sz  =  conjureWith args+                       {  maxSize = sz+                       ,  maxEquationSize = min sz (maxEquationSize args)+                       }++ -- | Arguments to be passed to 'conjureWith' or 'conjpureWith'. --   See 'args' for the defaults. data Args = Args@@ -51,6 +98,7 @@   , forceTests :: [[Expr]]  -- ^ force tests   } + -- | Default arguments to conjure. -- -- * 60 tests@@ -70,6 +118,29 @@   , forceTests         =  []   } ++-- | Like 'conjure' but allows setting options through 'Args'/'args'.+--+-- > conjureWith args{maxSize = 11} "function" function [...]+conjureWith :: Conjurable f => Args -> String -> f -> [Expr] -> IO ()+conjureWith args nm f es  =  do+  print (var (head $ words nm) f)+  putStrLn $ "-- testing " ++ show (length ts) ++ " combinations of argument values"+  pr 1 rs+  where+  pr n []  =  putStrLn $ "cannot conjure"+  pr n ((is,cs,es):rs)  =  do+    putStrLn $ "-- looking through "+            ++ show (length cs) ++ "/" ++ show (length es)+            ++ " candidates of size " ++ show n+    case is of+      []     ->  pr (n+1) rs+      (i:_)  ->  do putStrLn $ showEq i+                    putStrLn ""+  rs  =  zip3 iss css ess+  (iss, css, ess, ts)  =  conjpureWith args nm f es++ -- | Like 'conjure' but in the pure world. -- -- Returns a triple with:@@ -81,6 +152,7 @@ conjpure :: Conjurable f => String -> f -> [Expr] -> ([[Expr]], [[Expr]], [[Expr]], [Expr]) conjpure =  conjpureWith args + -- | Like 'conjpure' but allows setting options through 'Args' and 'args'. conjpureWith :: Conjurable f => Args -> String -> f -> [Expr] -> ([[Expr]], [[Expr]], [[Expr]], [Expr]) conjpureWith Args{..} nm f es  =  (implementationsT, candidatesT, allCandidatesT, tests)@@ -111,75 +183,7 @@     where     e  =  ffxx -==- ffxx --- | Conjures an implementation of a partially defined function.------ Takes a 'String' with the name of a function,--- a partially-defined function from a conjurable type,--- and a list of building blocks encoded as 'Expr's.------ For example, given:------ > square :: Int -> Int--- > square 0  =  0--- > square 1  =  1--- > square 2  =  4--- >--- > primitives :: [Expr]--- > primitives =--- >   [ val (0::Int)--- >   , val (1::Int)--- >   , value "+" ((+) :: Int -> Int -> Int)--- >   , value "*" ((*) :: Int -> Int -> Int)--- > ]------ The conjure function does the following:------ > > conjure "square" square primitives--- > square :: Int -> Int--- > -- testing 3 combinations of argument values--- > -- looking through 3 candidates of size 1--- > -- looking through 3 candidates of size 2--- > -- looking through 5 candidates of size 3--- > square x  =  x * x------ The primitives list is defined with 'val' and 'value'.-conjure :: Conjurable f => String -> f -> [Expr] -> IO ()-conjure  =  conjureWith args --- | Like 'conjure' but allows setting the maximum size of considered expressions---   instead of the default value of 9.------ > conjureWithMaxSize 10 "function" function [...]-conjureWithMaxSize :: Conjurable f => Int -> String -> f -> [Expr] -> IO ()-conjureWithMaxSize sz  =  conjureWith args-                       {  maxSize = sz-                       ,  maxEquationSize = min sz (maxEquationSize args)-                       }------ | Like 'conjure' but allows setting options through 'Args'/'args'.------ > conjureWith args{maxSize = 11} "function" function [...]-conjureWith :: Conjurable f => Args -> String -> f -> [Expr] -> IO ()-conjureWith args nm f es  =  do-  print (var (head $ words nm) f)-  putStrLn $ "-- testing " ++ show (length ts) ++ " combinations of argument values"-  pr 1 rs-  where-  pr n []  =  putStrLn $ "cannot conjure"-  pr n ((is,cs,es):rs)  =  do-    putStrLn $ "-- looking through "-            ++ show (length cs) ++ "/" ++ show (length es)-            ++ " candidates of size " ++ show n-    case is of-      []     ->  pr (n+1) rs-      (i:_)  ->  do putStrLn $ showEq i-                    putStrLn ""-  rs  =  zip3 iss css ess-  (iss, css, ess, ts)  =  conjpureWith args nm f es-  showEq eq  =  showExpr (lhs eq) ++ "  =  " ++ showExpr (rhs eq)- candidateExprs :: Conjurable f                => String -> f                -> Int@@ -190,6 +194,7 @@ candidateExprs nm f sz mc (===) es  =   candidateExprsT nm f sz mc (===) [nub $ es ++ conjureIfs f] + candidateExprsT :: Conjurable f                 => String -> f                 -> Int@@ -197,44 +202,42 @@                 -> (Expr -> Expr -> Bool)                 -> [[Expr]]                 -> [[Expr]]-candidateExprsT nm f sz mc (===) ess  =  expressionsT $ [ef:exs] \/ ess+candidateExprsT nm f sz mc (===) ess  =+  candidateExprsTT keep $ [ef:exs] \/ ess   where   (ef:exs)  =  unfoldApp $ conjureVarApplication nm f+  keep e  =  isRootNormalE thy e && count (== ef) (vars e) <= mc+  thy  =  theoryFromAtoms (===) sz $ [conjureHoles f ++ falseAndTrue]+                                  \/ filterT (`notElem` falseAndTrue) ess   falseAndTrue  =  [val False, val True]-  thy  =  theoryFromAtoms (===) sz $ [conjureHoles f ++ falseAndTrue] \/ filterT (`notElem` falseAndTrue) ess-  nubET  =  id -- no nub, good enough results-  -- nubET  =  discardLaterT (===) -- huge computational cost-  expressionsT ds  =  nubET-                   $  filterT (\e -> count (== ef) (vars e) <= mc)-                   $  filterT (isRootNormalE thy)-                   $  ds \/ (delay $ productMaybeWith ($$) es es)-    where-    es = expressionsT ds -lhs, rhs :: Expr -> Expr-lhs (((Value "==" _) :$ e) :$ _)  =  e-rhs (((Value "==" _) :$ _) :$ e)  =  e -compareResult :: (Int,Expr) -> (Int,Expr) -> Ordering-compareResult (n1,e1) (n2,e2)  =  n2 `compare` n1-                               <> e1 `compareSimplicity` e2+candidateExprsTT :: (Expr -> Bool) -> [[Expr]] -> [[Expr]]+candidateExprsTT keep  =  exprT+  where+  exprT ess  =  filterT keep+             $  ess \/ (delay $ productMaybeWith ($$) rss rss)+    where+    rss = exprT ess -(%) :: Int -> Int -> Int-x % y  =  x * 100 `div` y --- Debug: application that always works-(*$$*) :: Expr -> Expr -> Maybe Expr-e1 *$$* e2  =  Just $ e1 :$ e2---- Debug: application that works for the correct kinds-(>$$<) :: Expr -> Expr -> Maybe Expr-e1 >$$< e2  =  if isFunTy t1 && tyArity (argumentTy t1) == tyArity t2-               then Just $ e1 :$ e2-               else Nothing+candidatesTD :: (Expr -> Bool) -> Expr -> [Expr] -> [[Expr]]+candidatesTD keep h primitives  =  filterT (not . hasHole)+                                $  town [[h]]   where-  t1  =  ktyp e1-  t2  =  ktyp e2+  most = mostGeneralCanonicalVariation -ktyp :: Expr -> TypeRep-ktyp (e1 :$ e2)  =  resultTy (ktyp e1)-ktyp e  =  typ e+  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
src/Conjure/Expr.hs view
@@ -11,6 +11,7 @@   ( module Data.Express   , module Data.Express.Fixtures +  , (>$$<)   , funToVar   , recursexpr   , apparentlyTerminates@@ -18,6 +19,16 @@   , applicationOld   , compareSimplicity   , ifFor+  , primitiveHoles+  , primitiveApplications+  , valuesBFS+  , holesBFS+  , fillBFS+  , showEq+  , lhs+  , rhs+  , ($$**)+  , ($$|<)    , module Conjure.Utils   )@@ -26,6 +37,7 @@ import Conjure.Utils  import Data.Express+import Data.Express.Utils.Typeable import Data.Express.Fixtures hiding ((-==-))  -- | /O(n)/.@@ -172,3 +184,78 @@ -- if you want recursive functions to be considered and produced. ifFor :: Typeable a => a -> Expr ifFor a  =  value "if" (\p x y -> if p then x else y `asTypeOf` a)++-- | Application cross-product between lists of Exprs+(>$$<) :: [Expr] -> [Expr] -> [Expr]+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+valuesBFS :: Expr -> [Expr]+valuesBFS  =  concat . bfs+  where+  bfs :: Expr -> [[Expr]]+  bfs (ef :$ ex)  =  [] : mzip (bfs ef) (bfs ex)+  bfs e  =  [[e]]++-- lists holes in BFS order+holesBFS :: Expr -> [Expr]+holesBFS  =  filter isHole . valuesBFS++fillBFS :: Expr -> Expr -> Expr+fillBFS e e'  =  fst (f e)+  where+  f :: Expr -> (Expr,Maybe Int)+  f (ef :$ ex)  =  case (mf, mx) of+    (Nothing, Nothing)             -> (ef :$ ex, Nothing)+    (Just lf, Nothing)             -> (ef' :$ ex, Just $ lf+1)+    (Nothing, Just lx)             -> (ef :$ ex', Just $ lx+1)+    (Just lf, Just lx) | lf <= lx  -> (ef' :$ ex, Just $ lf+1)+                       | otherwise -> (ef :$ ex', Just $ lx+1)+    where+    (ef', mf)  =  f ef+    (ex', mx)  =  f ex+  f e | isHole e && typ e == typ e'  =  (e', Just 0)+      | 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+($$**) :: Expr -> Expr -> Maybe Expr+e1 $$** e2  =  Just $ e1 :$ e2++-- Debug: application that works for the correct kinds+($$|<) :: Expr -> Expr -> Maybe Expr+e1 $$|< e2  =  if isFunTy t1 && tyArity (argumentTy t1) == tyArity t2+               then Just $ e1 :$ e2+               else Nothing+  where+  t1  =  ktyp e1+  t2  =  ktyp e2++  ktyp :: Expr -> TypeRep+  ktyp (e1 :$ e2)  =  resultTy (ktyp e1)+  ktyp e  =  typ e
src/Conjure/Spec.hs view
@@ -97,7 +97,7 @@ -- > xs ++ ys  =  if null xs then ys else head xs:(tail xs ++ ys) -- -- (cf. 'Spec1', 'conjure1With')-conjure1 :: (Eq a, Show a, Conjurable a, Conjurable b)+conjure1 :: (Eq a, Eq b, Show a, Conjurable a, Conjurable b)          => String -> Spec1 a b -> [Expr] -> IO () conjure1  =  conjure1With args @@ -133,7 +133,7 @@ -- (cf. 'Spec2', 'conjure2With') conjure2 :: ( Conjurable a, Eq a, Show a             , Conjurable b, Eq b, Show b-            , Conjurable c+            , Conjurable c, Eq c             ) => String -> Spec2 a b c -> [Expr] -> IO () conjure2  =  conjure2With args @@ -144,13 +144,13 @@ conjure3 :: ( Conjurable a, Eq a, Show a             , Conjurable b, Eq b, Show b             , Conjurable c, Eq c, Show c-            , Conjurable d+            , Conjurable d, Eq d             ) => String -> Spec3 a b c d -> [Expr] -> IO () conjure3  =  conjure3With args   -- | Like 'conjure1' but allows setting options through 'Args'/'args'.-conjure1With :: (Eq a, Show a, Conjurable a, Conjurable b)+conjure1With :: (Eq a, Eq b, Show a, Conjurable a, Conjurable b)              => Args -> String -> Spec1 a b -> [Expr] -> IO () conjure1With args nm bs  =  conjureWith args{forceTests=ts} nm (mkFun1 bs)   where@@ -160,7 +160,7 @@ -- | Like 'conjure2' but allows setting options through 'Args'/'args'. conjure2With :: ( Conjurable a, Eq a, Show a                 , Conjurable b, Eq b, Show b-                , Conjurable c+                , Conjurable c, Eq c                 ) => Args -> String -> Spec2 a b c -> [Expr] -> IO () conjure2With args nm bs  =  conjureWith args{forceTests=ts} nm (mkFun2 bs)   where@@ -171,7 +171,7 @@ conjure3With :: ( Conjurable a, Eq a, Show a                 , Conjurable b, Eq b, Show b                 , Conjurable c, Eq c, Show c-                , Conjurable d+                , Conjurable d, Eq d                 ) => Args -> String -> Spec3 a b c d -> [Expr] -> IO () conjure3With args nm bs  =  conjureWith args{forceTests=ts} nm (mkFun3 bs)   where
src/Conjure/Utils.hs view
@@ -18,6 +18,8 @@    , count   , nubOn+  , iterateUntil+  , mzip   ) where @@ -33,3 +35,17 @@  nubOn :: Eq b => (a -> b) -> [a] -> [a] nubOn f  =  nubBy ((==) `on` f)++iterateUntil :: (a -> a -> Bool) -> (a -> a) -> a -> a+iterateUntil (?) f  =  iu+  where+  iu x | x ? fx     =  x+       | otherwise  =  iu fx+    where+    fx  =  f x++mzip :: Monoid a => [a] -> [a] -> [a]+mzip [] []  =  []+mzip [] ys  =  ys+mzip xs []  =  xs+mzip (x:xs) (y:ys)  =  x <> y : mzip xs ys
test/Test.hs view
@@ -11,6 +11,9 @@   , module Conjure.Expr   , module Conjure.Conjurable   , module Test.LeanCheck+  , module Test.LeanCheck.Utils+  , module Test.ListableExpr+  , module Test.Candidates    , mainTest   )@@ -20,6 +23,9 @@ import System.Environment (getArgs)  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 view
@@ -0,0 +1,60 @@+-- |+-- 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/Test/ListableExpr.hs view
@@ -0,0 +1,285 @@+-- |+-- Module      : Test.ListableExpr+-- Copyright   : (c) 2019-2021 Rudy Matela+-- License     : 3-Clause BSD  (see the file LICENSE)+-- Maintainer  : Rudy Matela <rudy@matela.com.br>+--+-- This module exports a 'Listable' 'Expr' instance.+-- This instance does not, by any means, list all possible expressions.+-- It lists expressions based on a subset of the symbols exported by+-- "Data.Express.Fixtures".+--+-- This is only intended to be used for testing,+-- so this will not be exported on @ express.cabal @.+module Test.ListableExpr+  (+  -- * The Expr type+    Expr++  -- * Expressions of a type+  , IntE (..)+  , BoolE (..)+  , IntsE (..)+  , CharE (..)++  , IntE0 (..)+  , IntEV (..)+  , BoolE0 (..)+  , BoolEV (..)+  , IntsE0 (..)+  , IntsEV (..)+  , CharE0 (..)+  , CharEV (..)++  -- ** Functional values+  , IntToIntE (..)+  , IntToIntToIntE (..)+  , BoolToBoolE (..)+  , BoolToBoolToBoolE (..)++  , SameTypeE (..)+  , unSameTypeE+  , SameTypedPairsE (..)++  -- * Terminal expressions+  , E0 (..)+  , EV (..)++  -- * Ill typed expressions+  , Ill (..)+  )+where++-- TODO: StringE++import Test.LeanCheck+import Test.LeanCheck.Function.ShowFunction+import Data.Express.Fixtures+import Data.Function (on)++-- | Terminal constants.+newtype E0  =  E0 { unE0 :: Expr }++-- | Variables.+newtype EV  =  EV { unEV :: Expr }++-- | Expression of 'Int' type.+newtype IntE  =  IntE { unIntE :: Expr }++-- | Constant terminal value of 'Int' type.+newtype IntE0  =  IntE0 { unIntE0 :: Expr }++-- | Variable of 'Int' type.+newtype IntEV  =  IntEV { unIntEV :: Expr }++-- | Functions from Int to Int+newtype IntToIntE  =  IntToIntE { unIntToIntE :: Expr }+newtype IntToIntToIntE  =  IntToIntToIntE { unIntToIntToIntE :: Expr }++-- | Expression of 'Bool' type.+newtype BoolE  =  BoolE { unBoolE :: Expr }++-- | Constant terminal value of 'Bool' type.+newtype BoolE0  =  BoolE0 { unBoolE0 :: Expr }++-- | Varialbe of 'Bool' type.+newtype BoolEV  =  BoolEV { unBoolEV :: Expr }++-- | Functions from Bool to Bool+newtype BoolToBoolE  =  BoolToBoolE { unBoolToBoolE :: Expr }+newtype BoolToBoolToBoolE  =  BoolToBoolToBoolE { unBoolToBoolToBoolE :: Expr }++newtype CharE  =  CharE { unCharE :: Expr }++newtype CharE0  =  CharE0 { unCharE0 :: Expr }++newtype CharEV  =  CharEV { unCharEV :: Expr }++data SameTypeE  =  SameTypeE Expr Expr++unSameTypeE :: SameTypeE -> (Expr,Expr)+unSameTypeE (SameTypeE e1 e2)  =  (e1,e2)++data SameTypedPairsE  =  SameTypedPairsE { unSameTypedPairsE :: [(Expr,Expr)] }++-- | Ill typed expressions.+newtype Ill  =  Ill { unIll :: Expr }+++instance Show E0  where  show (E0 e) = show e+instance Show EV  where  show (EV e) = show e++instance Show IntE  where  show (IntE e) = show e++instance Show IntE0  where  show (IntE0 e) = show e+instance Show IntEV  where  show (IntEV e) = show e++instance Show IntToIntE  where  show (IntToIntE e) = show e+instance Show IntToIntToIntE  where  show (IntToIntToIntE e) = show e++instance Show BoolE  where  show (BoolE e) = show e++instance Show BoolE0  where  show (BoolE0 e) = show e+instance Show BoolEV  where  show (BoolEV e) = show e++instance Show BoolToBoolE  where  show (BoolToBoolE e) = show e+instance Show BoolToBoolToBoolE  where  show (BoolToBoolToBoolE e) = show e++instance Show IntsE  where  show (IntsE e) = show e++instance Show IntsE0  where  show (IntsE0 e) = show e+instance Show IntsEV  where  show (IntsEV e) = show e++instance Show CharE  where  show (CharE e) = show e++instance Show CharE0  where  show (CharE0 e) = show e+instance Show CharEV  where  show (CharEV e) = show e++instance Show SameTypeE  where  show (SameTypeE e1 e2) = show (e1,e2)++instance Show SameTypedPairsE  where  show (SameTypedPairsE ees)  =  show ees++-- | Expression of 'Ints' type.+newtype IntsE  =  IntsE { unIntsE :: Expr }++-- | Constant terminal value of 'Ints' type.+newtype IntsE0  =  IntsE0 { unIntsE0 :: Expr }++-- | Varialbe of 'Ints' type.+newtype IntsEV  =  IntsEV { unIntsEV :: Expr }++instance Show Ill where  show (Ill e) = show e++instance Listable IntE  where+  tiers  =  mapT IntE+         $  cons0 i_+         \/ cons1 unIntEV+         \/ cons1 unIntE0+         \/ cons2 (\(IntToIntE f) (IntE xx) -> f :$ xx)+         \/ cons1 (head' . unIntsE) `ofWeight` 2+         \/ cons1 (ord' . unCharE) `ofWeight` 2++instance Listable IntE0 where+  tiers  =  (IntE0 . val) `mapT` (tiers :: [[Int]])++instance Listable IntEV where+  list  =  map IntEV $ listVars "x" (undefined :: Int)++instance Listable IntToIntE where+  tiers  =  mapT IntToIntE+         $  cons0 idE+         \/ cons0 negateE `addWeight` 1+         \/ cons0 absE    `addWeight` 1+         \/ cons2 (\(IntToIntToIntE ef) (IntE ex) -> ef :$ ex)+         \/ toTiers (listVars "f" (undefined :: Int -> Int)) `addWeight` 2++instance Listable IntToIntToIntE where+  list  =  map IntToIntToIntE [plus, times]++instance Listable IntsE  where+  tiers  =  mapT IntsE+         $  cons0 is_+         \/ cons1 unIntsEV+         \/ cons1 unIntsE0+         \/ cons2 (\(IntE ex) (IntsE exs) -> ex -:- exs)+         \/ cons1 (tail' . unIntsE) `ofWeight` 2+         \/ cons2 (\(IntsE exs) (IntsE eys) -> exs -++- eys) `ofWeight` 2+         \/ cons1 (\(IntsE exs) -> sort' exs) `ofWeight` 3+         \/ cons2 (\(IntE ex) (IntsE exs) -> insert' ex exs) `ofWeight` 3++instance Listable IntsE0 where+  tiers  =  (IntsE0 . val) `mapT` (tiers :: [[ [Int] ]])++instance Listable IntsEV where+  list  =  map IntsEV $ listVars "xs" (undefined :: [Int])++instance Listable BoolE  where+  tiers  =  mapT BoolE+         $  cons0 b_+         \/ cons1 unBoolEV+         \/ cons1 unBoolE0+         \/ cons2 (\(BoolToBoolE ef) (BoolE ep) -> ef :$ ep)+         \/ cons2 ((-==-) `on` unIntE)  `addWeight` 2+         \/ cons2 ((-==-) `on` unBoolE) `addWeight` 2+         \/ cons2 ((-<=-) `on` unIntE)  `addWeight` 3+         \/ cons2 ((-<=-) `on` unBoolE) `addWeight` 3+         \/ cons2 ((-<-)  `on` unIntE)  `addWeight` 4+         \/ cons2 ((-<-)  `on` unBoolE) `addWeight` 4+         \/ cons2 ((-/=-) `on` unIntE)  `addWeight` 5+         \/ cons2 ((-/=-) `on` unBoolE) `addWeight` 5+         \/ cons1 (odd'  . unIntE) `addWeight` 2+         \/ cons1 (even' . unIntE) `addWeight` 2+         \/ cons2 (\(IntE ex) (IntsE exs) -> elem' ex exs) `addWeight` 2++instance Listable BoolE0 where+  tiers  =  (BoolE0 . val) `mapT` (tiers :: [[Bool]])++instance Listable BoolEV where+  list  =  map BoolEV $ listVars "p" (undefined :: Bool)++instance Listable BoolToBoolE where+  tiers  =  mapT BoolToBoolE+         $  cons0 notE+         \/ cons2 (\(BoolToBoolToBoolE ef) (BoolE ex) -> ef :$ ex)++instance Listable BoolToBoolToBoolE where+  list  =  map BoolToBoolToBoolE [orE, andE, implies]++instance Listable CharE where+  tiers  =  mapT CharE $ cons0 c_+                      \/ cons1 unCharEV+                      \/ cons1 unCharE0++instance Listable CharEV where+  list  =  map CharEV $ listVars "c" (undefined :: Char)++instance Listable CharE0 where+  tiers  =  (CharE0 . val) `mapT` (tiers :: [[Char]])++instance Listable SameTypeE where+  tiers = cons1 (\(IntE  e1, IntE  e2) -> SameTypeE e1 e2) `ofWeight` 0+       \/ cons1 (\(BoolE e1, BoolE e2) -> SameTypeE e1 e2) `ofWeight` 1+       \/ cons1 (\(IntsE e1, IntsE e2) -> SameTypeE e1 e2) `ofWeight` 1+       \/ cons1 (\(CharE e1, CharE e2) -> SameTypeE e1 e2) `ofWeight` 2+       \/ cons1 (\(IntToIntE e1, IntToIntE e2)     -> SameTypeE e1 e2) `ofWeight` 2+       \/ cons1 (\(BoolToBoolE e1, BoolToBoolE e2) -> SameTypeE e1 e2) `ofWeight` 2+       \/ cons1 (\(BoolToBoolToBoolE e1, BoolToBoolToBoolE e2) -> SameTypeE e1 e2) `ofWeight` 2+       \/ cons1 (\(IntToIntToIntE e1, IntToIntToIntE e2)       -> SameTypeE e1 e2) `ofWeight` 2++instance Listable SameTypedPairsE where+  tiers = cons1 (SameTypedPairsE . map unSameTypeE) `ofWeight` 0++instance Listable E0 where+  tiers  =  mapT E0+         $  cons1 unIntE0  `ofWeight` 0+         \/ cons1 unBoolE0 `ofWeight` 1+         \/ cons1 unIntsE0 `ofWeight` 1++instance Listable EV where+  tiers  =  mapT EV+         $  cons1 unIntEV  `ofWeight` 0+         \/ cons1 unBoolEV `ofWeight` 1+         \/ cons1 unIntsEV `ofWeight` 1+++instance Listable Expr where+  tiers  =  reset (cons1 unIntE)+         \/ cons1 unBoolE+         \/ cons1 unCharE+         \/ cons1 unIntsE+         \/ cons1 unIntToIntE         `addWeight` 1+         \/ cons1 unIntToIntToIntE    `addWeight` 1+         \/ cons1 unBoolToBoolE       `addWeight` 2+         \/ cons1 unBoolToBoolToBoolE `addWeight` 2+++-- | This listable instance only produces Ill typed expressions+instance Listable Ill where+  tiers  =  mapT Ill+         $  cons2 (\(IntE ef) (IntE ex) -> ef :$ ex) `ofWeight` 0+         \/ cons2 (\(IntToIntE ef) (IntToIntE ex) -> ef :$ ex)+         \/ cons2 (\(Ill ef) ex -> ef :$ ex)+         \/ cons2 (\ef (Ill ex)-> ef :$ ex)+++instance ShowFunction Expr where bindtiers  =  bindtiersShow
test/expr.hs view
@@ -34,4 +34,129 @@   , apparentlyTerminates ffE (if' pp zero (ff xx)) == True   , apparentlyTerminates ffE (if' pp (ff xx) zero) == False   , apparentlyTerminates ffE (if' (odd' (ff xx)) zero zero) == False++  , [false, true, zero, one] >$$< [notE, andE, orE, plus, times] == []+  , [notE, andE, orE, plus, times] >$$< [false, true, zero, one]+    == [ not' false+       , not' true+       , andE :$ false+       , andE :$ true+       , orE :$ false+       , orE :$ true+       , plus :$ zero+       , plus :$ one+       , times :$ zero+       , times :$ one+       ]+  , [notE, andE, orE, plus, times] >$$< [false, true, zero, one] >$$< [false, true, zero, one]+    == [ false -&&- false+       , false -&&- true+       , true -&&- false+       , true -&&- true+       , false -||- false+       , false -||- true+       , true -||- false+       , true -||- true+       , zero -+- zero+       , zero -+- one+       , one -+- zero+       , one -+- one+       , zero -*- zero+       , zero -*- one+       , one -*- zero+       , 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]+  , valuesBFS true  == [true]+  , valuesBFS zero  == [zero]+  , valuesBFS one   == [one]+  , valuesBFS (not' false) == [notE, false]+  , valuesBFS (not' true)  == [notE, true]+  , valuesBFS (not' $ not' true) == [notE, notE, true]+  , valuesBFS (false -&&- true) == [true, andE, false]+  , valuesBFS (true -||- false) == [false, orE, true]+  , valuesBFS (one -*- two -+- three -*- xx)+    == [plus, xx, two, times, three, times, one]+    -- (((+) (((*) 1) 2)) (((*) 3) x))++  , fillBFS (b_ -&&- b_) false == (b_ -&&- false)+  , fillBFS (b_ -&&- b_) (b_ -&&- b_) == (b_ -&&- (b_ -&&- b_))+  , fillBFS (b_ -&&- (b_ -&&- b_)) false == (false -&&- (b_ -&&- b_))+  , fillBFS (b_ -&&- (b_ -&&- b_)) (b_ -&&- b_) == ((b_ -&&- b_) -&&- (b_ -&&- b_))+  , fillBFS ((b_ -&&- b_) -&&- (b_ -&&- b_)) false == ((b_ -&&- b_) -&&- (b_ -&&- false))+  , fillBFS true false == true++  , holds n $ \(SameTypeE e1 e2) -> let e3 = fillBFS e1 e2+                                    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   ]
test/model/proto/u-conjure.out view
@@ -4,15 +4,21 @@ add :: Int -> Int -> Int add x y  =  x + y -fact :: Int -> Int+factorial :: Int -> Int cannot conjure -(==>) :: Bool -> Bool -> Bool-p ==> q  =  q || not p+factorial :: Int -> Int+factorial x  =  foldr (*) 1 (enumFromTo 1 x)  second :: [Int] -> Int second xs  =  head (tail xs) +(++) :: [Int] -> [Int] -> [Int]+xs ++ ys  =  foldr (:) ys xs+ reverse :: [Int] -> [Int] cannot conjure++reverse :: [Int] -> [Int]+reverse xs  =  foldr (foldr (:) . unit) [] xs 
+ test/utils.hs view
@@ -0,0 +1,21 @@+-- Copyright (C) 2021 Rudy Matela+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).++import Test++main :: IO ()+main  =  mainTest tests 5040++tests :: Int -> [Bool]+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]])+  ]