Copyright | (c) 2016-2024 Rudy Matela |
---|---|
License | 3-Clause BSD (see the file LICENSE) |
Maintainer | Rudy Matela <rudy@matela.com.br> |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
Speculate: discovery of properties by reasoning from test results
Speculate automatically discovers laws about Haskell functions. Those laws involve:
- equations, such as
id x == x
; - inequalities, such as
0 <= x * x
; - conditional equations, such as
x <= 0 ==> x + abs x == 0
.
_Example:_ the following program prints laws about 0
, 1
, +
and abs
.
import Test.Speculate main :: IO () main = speculate args { constants = [ showConstant (0::Int) , showConstant (1::Int) , constant "+" ((+) :: Int -> Int -> Int) , constant "abs" (abs :: Int -> Int) , background , constant "<=" ((<=) :: Int -> Int -> Bool) ] }
Synopsis
- speculate :: Args -> IO ()
- data Args = Args {
- maxSize :: Int
- maxTests :: Int
- constants :: [Expr]
- instances :: [Instances]
- maxSemiSize :: Int
- maxCondSize :: Int
- maxVars :: Int
- showConstants :: Bool
- showEquations :: Bool
- showSemiequations :: Bool
- showConditions :: Bool
- showConstantLaws :: Bool
- autoConstants :: Bool
- minTests :: Int -> Int
- maxConstants :: Maybe Int
- maxDepth :: Maybe Int
- showCounts :: Bool
- showTheory :: Bool
- showArgs :: Bool
- showHelp :: Bool
- evalTimeout :: Maybe Double
- force :: Bool
- extra :: [String]
- exclude :: [String]
- onlyTypes :: [String]
- showClassesFor :: [Int]
- showDot :: Bool
- quietDot :: Bool
- args :: Args
- data Expr
- constant :: Typeable a => String -> a -> Expr
- showConstant :: (Typeable a, Show a) => a -> Expr
- hole :: Typeable a => a -> Expr
- foreground :: Expr
- background :: Expr
- type Instances = [Expr]
- reifyInstances :: (Typeable a, Listable a, Show a, Eq a, Ord a, Name a) => a -> Instances
- reifyEq :: (Typeable a, Eq a) => a -> [Expr]
- reifyOrd :: (Typeable a, Ord a) => a -> [Expr]
- reifyEqOrd :: (Typeable a, Ord a) => a -> [Expr]
- reifyListable :: (Typeable a, Show a, Listable a) => a -> Instances
- reifyName :: (Typeable a, Name a) => a -> [Expr]
- mkEq :: Typeable a => (a -> a -> Bool) -> [Expr]
- mkOrd :: Typeable a => (a -> a -> Ordering) -> [Expr]
- mkOrdLessEqual :: Typeable a => (a -> a -> Bool) -> [Expr]
- mkListable :: (Typeable a, Show a) => [[a]] -> [Expr]
- mkNameWith :: Typeable a => String -> a -> [Expr]
- class Name a where
- report :: Args -> IO ()
- getArgs :: Args -> IO Args
- module Test.LeanCheck
- module Test.LeanCheck.Utils
- module Data.Typeable
Documentation
speculate :: Args -> IO () Source #
Calls Speculate. See the example above (at the top of the file).
Its only argument is an Args
structure.
Arguments to Speculate
Args | |
|
The constants list
Values of type Expr
represent objects or applications between objects.
Each object is encapsulated together with its type and string representation.
Values encoded in Expr
s are always monomorphic.
An Expr
can be constructed using:
val
, for values that areShow
instances;value
, for values that are notShow
instances, like functions;:$
, for applications betweenExpr
s.
> val False False :: Bool
> value "not" not :$ val False not False :: Bool
An Expr
can be evaluated using evaluate
, eval
or evl
.
> evl $ val (1 :: Int) :: Int 1
> evaluate $ val (1 :: Int) :: Maybe Bool Nothing
> eval 'a' (val 'b') 'b'
Show
ing a value of type Expr
will return a pretty-printed representation
of the expression together with its type.
> show (value "not" not :$ val False) "not False :: Bool"
Expr
is like Dynamic
but has support for applications and variables
(:$
, var
).
The var
underscore convention:
Functions that manipulate Expr
s usually follow the convention
where a value
whose String
representation starts with '_'
represents a var
iable.
Instances
Show Expr | Shows > show (value "not" not :$ val False) "not False :: Bool" |
Eq Expr | O(n). Does not evaluate values when comparing, but rather uses their representation as strings and their types. This instance works for ill-typed expressions. |
Ord Expr | O(n). Does not evaluate values when comparing, but rather uses their representation as strings and their types. This instance works for ill-typed expressions. Expressions come first
when they have smaller complexity ( |
hole :: Typeable a => a -> Expr #
O(1).
Creates an Expr
representing a typed hole of the given argument type.
> hole (undefined :: Int) _ :: Int
> hole (undefined :: Maybe String) _ :: Maybe [Char]
A hole is represented as a variable with no name or
a value named "_"
:
hole x = var "" x hole x = value "_" x
foreground :: Expr Source #
A special Expr
value.
When provided on the constants
list,
makes all the following constants foreground
constants.
background :: Expr Source #
A special Expr
value.
When provided on the constants
list,
makes all the following constants background
constants.
Background constants can appear in laws about other constants, but not by
themselves.
The instances list
reifyEq :: (Typeable a, Eq a) => a -> [Expr] #
O(1).
Reifies an Eq
instance into a list of Expr
s.
The list will contain ==
and /=
for the given type.
(cf. mkEq
, mkEquation
)
> reifyEq (undefined :: Int) [ (==) :: Int -> Int -> Bool , (/=) :: Int -> Int -> Bool ]
> reifyEq (undefined :: Bool) [ (==) :: Bool -> Bool -> Bool , (/=) :: Bool -> Bool -> Bool ]
> reifyEq (undefined :: String) [ (==) :: [Char] -> [Char] -> Bool , (/=) :: [Char] -> [Char] -> Bool ]
reifyOrd :: (Typeable a, Ord a) => a -> [Expr] #
O(1).
Reifies an Ord
instance into a list of Expr
s.
The list will contain compare
, <=
and <
for the given type.
(cf. mkOrd
, mkOrdLessEqual
, mkComparisonLE
, mkComparisonLT
)
> reifyOrd (undefined :: Int) [ (<=) :: Int -> Int -> Bool , (<) :: Int -> Int -> Bool ]
> reifyOrd (undefined :: Bool) [ (<=) :: Bool -> Bool -> Bool , (<) :: Bool -> Bool -> Bool ]
> reifyOrd (undefined :: [Bool]) [ (<=) :: [Bool] -> [Bool] -> Bool , (<) :: [Bool] -> [Bool] -> Bool ]
reifyEqOrd :: (Typeable a, Ord a) => a -> [Expr] #
reifyName :: (Typeable a, Name a) => a -> [Expr] #
O(1).
Reifies a Name
instance into a list of Expr
s.
The list will contain name
for the given type.
(cf. mkName
, lookupName
, lookupNames
)
> reifyName (undefined :: Int) [name :: Int -> [Char]]
> reifyName (undefined :: Bool) [name :: Bool -> [Char]]
mkOrd :: Typeable a => (a -> a -> Ordering) -> [Expr] #
O(1).
Builds a reified Ord
instance from the given compare
function.
(cf. reifyOrd
, mkOrdLessEqual
)
mkOrdLessEqual :: Typeable a => (a -> a -> Bool) -> [Expr] #
mkNameWith :: Typeable a => String -> a -> [Expr] #
If we were to come up with a variable name for the given type
what name
would it be?
An instance for a given type Ty
is simply given by:
instance Name Ty where name _ = "x"
Examples:
> name (undefined :: Int) "x"
> name (undefined :: Bool) "p"
> name (undefined :: [Int]) "xs"
This is then used to generate an infinite list of variable names
:
> names (undefined :: Int) ["x", "y", "z", "x'", "y'", "z'", "x''", "y''", "z''", ...]
> names (undefined :: Bool) ["p", "q", "r", "p'", "q'", "r'", "p''", "q''", "r''", ...]
> names (undefined :: [Int]) ["xs", "ys", "zs", "xs'", "ys'", "zs'", "xs''", "ys''", ...]
Nothing
O(1).
Returns a name for a variable of the given argument's type.
> name (undefined :: Int) "x"
> name (undefined :: [Bool]) "ps"
> name (undefined :: [Maybe Integer]) "mxs"
The default definition is:
name _ = "x"
Instances
Name Int16 | |
Defined in Data.Express.Name | |
Name Int32 | |
Defined in Data.Express.Name | |
Name Int64 | |
Defined in Data.Express.Name | |
Name Int8 | |
Defined in Data.Express.Name | |
Name GeneralCategory | |
Defined in Data.Express.Name name :: GeneralCategory -> String # | |
Name Word16 | |
Defined in Data.Express.Name | |
Name Word32 | |
Defined in Data.Express.Name | |
Name Word64 | |
Defined in Data.Express.Name | |
Name Word8 | |
Defined in Data.Express.Name | |
Name Ordering | name (undefined :: Ordering) = "o" names (undefined :: Ordering) = ["o", "p", "q", "o'", ...] |
Defined in Data.Express.Name | |
Name Integer | name (undefined :: Integer) = "x" names (undefined :: Integer) = ["x", "y", "z", "x'", ...] |
Defined in Data.Express.Name | |
Name () | name (undefined :: ()) = "u" names (undefined :: ()) = ["u", "v", "w", "u'", "v'", ...] |
Defined in Data.Express.Name | |
Name Bool | name (undefined :: Bool) = "p" names (undefined :: Bool) = ["p", "q", "r", "p'", "q'", ...] |
Defined in Data.Express.Name | |
Name Char | name (undefined :: Char) = "c" names (undefined :: Char) = ["c", "d", "e", "c'", "d'", ...] |
Defined in Data.Express.Name | |
Name Double | name (undefined :: Double) = "x" names (undefined :: Double) = ["x", "y", "z", "x'", ...] |
Defined in Data.Express.Name | |
Name Float | name (undefined :: Float) = "x" names (undefined :: Float) = ["x", "y", "z", "x'", ...] |
Defined in Data.Express.Name | |
Name Int | name (undefined :: Int) = "x" names (undefined :: Int) = ["x", "y", "z", "x'", "y'", ...] |
Defined in Data.Express.Name | |
Name Word | |
Defined in Data.Express.Name | |
Name (Complex a) | name (undefined :: Complex) = "x" names (undefined :: Complex) = ["x", "y", "z", "x'", ...] |
Defined in Data.Express.Name | |
Name (Ratio a) | name (undefined :: Rational) = "q" names (undefined :: Rational) = ["q", "r", "s", "q'", ...] |
Defined in Data.Express.Name | |
Name a => Name (Maybe a) | names (undefined :: Maybe Int) = ["mx", "mx1", "mx2", ...] nemes (undefined :: Maybe Bool) = ["mp", "mp1", "mp2", ...] |
Defined in Data.Express.Name | |
Name a => Name [a] | names (undefined :: [Int]) = ["xs", "ys", "zs", "xs'", ...] names (undefined :: [Bool]) = ["ps", "qs", "rs", "ps'", ...] |
Defined in Data.Express.Name | |
(Name a, Name b) => Name (Either a b) | names (undefined :: Either Int Int) = ["exy", "exy1", ...] names (undefined :: Either Int Bool) = ["exp", "exp1", ...] |
Defined in Data.Express.Name | |
(Name a, Name b) => Name (a, b) | names (undefined :: (Int,Int)) = ["xy", "zw", "xy'", ...] names (undefined :: (Bool,Bool)) = ["pq", "rs", "pq'", ...] |
Defined in Data.Express.Name | |
Name (a -> b) | names (undefined :: ()->()) = ["f", "g", "h", "f'", ...] names (undefined :: Int->Int) = ["f", "g", "h", ...] |
Defined in Data.Express.Name | |
(Name a, Name b, Name c) => Name (a, b, c) | names (undefined :: (Int,Int,Int)) = ["xyz","uvw", ...] names (undefined :: (Int,Bool,Char)) = ["xpc", "xpc1", ...] |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d) => Name (a, b, c, d) | names (undefined :: ((),(),(),())) = ["uuuu", "uuuu1", ...] names (undefined :: (Int,Int,Int,Int)) = ["xxxx", ...] |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e) => Name (a, b, c, d, e) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f) => Name (a, b, c, d, e, f) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g) => Name (a, b, c, d, e, f, g) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h) => Name (a, b, c, d, e, f, g, h) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h, Name i) => Name (a, b, c, d, e, f, g, h, i) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h, Name i, Name j) => Name (a, b, c, d, e, f, g, h, i, j) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h, Name i, Name j, Name k) => Name (a, b, c, d, e, f, g, h, i, j, k) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h, Name i, Name j, Name k, Name l) => Name (a, b, c, d, e, f, g, h, i, j, k, l) | |
Defined in Data.Express.Name |
Misc.
module Test.LeanCheck
module Test.LeanCheck.Utils
module Data.Typeable