-- | -- Module : Conjure -- Copyright : (c) 2021-2025 Rudy Matela -- License : 3-Clause BSD (see the file LICENSE) -- Maintainer : Rudy Matela <rudy@matela.com.br> -- -- A library for Conjuring function implementations -- from tests or partial definitions. -- (a.k.a.: functional inductive programming) -- -- Step 1: declare your partial function -- -- > factorial :: Int -> Int -- > factorial 2 = 2 -- > factorial 3 = 6 -- > factorial 4 = 24 -- -- Step 2: declare a list with the potential building blocks: -- -- > ingredients :: [Ingredient] -- > ingredients = -- > [ con (0::Int) -- > , con (1::Int) -- > , fun "+" ((+) :: Int -> Int -> Int) -- > , fun "*" ((*) :: Int -> Int -> Int) -- > , fun "-" ((-) :: Int -> Int -> Int) -- > ] -- -- Step 3: call 'conjure' and see your generated function: -- -- > > conjure "factorial" factorial ingredients -- > factorial :: Int -> Int -- > -- 0.1s, testing 4 combinations of argument values -- > -- 0.8s, pruning with 27/65 rules -- > -- 0.8s, 3 candidates of size 1 -- > -- 0.9s, 3 candidates of size 2 -- > -- 0.9s, 7 candidates of size 3 -- > -- 0.9s, 8 candidates of size 4 -- > -- 0.9s, 28 candidates of size 5 -- > -- 0.9s, 35 candidates of size 6 -- > -- 0.9s, 167 candidates of size 7 -- > -- 0.9s, tested 95 candidates -- > factorial 0 = 1 -- > factorial x = x * factorial (x - 1) -- -- The above example takes less than a second to run in a modern laptop. -- -- Factorial is discovered from scratch through a search. -- We prune the search space using properties discovered -- from the results of testing. -- -- Conjure is not limited to integers, -- it works for functions over algebraic data types too. -- See: -- -- > take' :: Int -> [a] -> [a] -- > take' 0 [x] = [] -- > take' 1 [x] = [x] -- > take' 0 [x,y] = [] -- > take' 1 [x,y] = [x] -- > take' 2 [x,y] = [x,y] -- > take' 3 [x,y] = [x,y] -- -- > > conjure "take" (take' :: Int -> [A] -> [A]) -- > > [ con (0 :: Int) -- > > , con (1 :: Int) -- > > , con ([] :: [A]) -- > > , fun ":" ((:) :: A -> [A] -> [A]) -- > > , fun "-" ((-) :: Int -> Int -> Int) -- > > ] -- > take :: Int -> [A] -> [A] -- > -- testing 153 combinations of argument values -- > -- pruning with 4/7 rules -- > -- ... ... ... ... ... ... -- > -- 0.4s, 6 candidates of size 8 -- > -- 0.4s, 5 candidates of size 9 -- > -- 0.4s, tested 15 candidates -- > take 0 xs = [] -- > take x [] = [] -- > take x (y:xs) = y:take (x - 1) xs -- -- The above example also takes less than a second to run in a modern laptop. -- The selection of functions in the list of ingredients was minimized -- to what was absolutely needed here. -- With a larger collection as ingredients YMMV. -- -- Conjure works for user-defined algebraic data types too, -- given that they are made instances of the 'Conjurable' typeclass. -- For types without data invariants, -- it should be enough to call 'deriveConjurable' -- to create an instance using TH. {-# LANGUAGE CPP #-} module Conjure ( -- * Basic use conjure , Ingredient , con , unfun , fun , guard , iif , ordcase -- * Basic configuration parameters , maxTests , target , maxSize -- * Conjuring from a specification , conjureFromSpec -- * When using custom types , Conjurable (conjureExpress, conjureEquality, conjureTiers, conjureCases, conjureSubTypes, conjureSize) , Expr , val , value , reifyExpress , reifyEquality , reifyTiers , conjureType , Name (..) , Express (..) , deriveConjurable , deriveConjurableIfNeeded , deriveConjurableCascading -- * Pure interfaces , Results (..) , conjpure -- * Helper test types , A, B, C, D, E, F -- * Advanced options , maxRecursions , maxEquationSize , maxSearchTests , maxDeconstructionSize , maxConstantSize , maxPatternSize , maxPatternDepth -- * Debug options , showCandidates , showTheory , singlePattern , showTests , showPatterns , showDeconstructions , carryOn -- * Advanced pruning options , dontRewrite , dontRequireDescent , omitAssortedPruning , omitEarlyTests , dontCopyBindings , nonAtomicNumbers , uniqueCandidates -- * Deprecated functions , Prim , pr , prim ) where import Conjure.Engine import Conjure.Conjurable import Conjure.Ingredient import Conjure.Conjurable.Derive import Conjure.Settings