speculate: discovery of properties about Haskell functions

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Warnings:

Speculate automatically discovers laws about Haskell functions. Give Speculate a bunch of Haskell functions and it will discover laws like:


[Skip to Readme]

Properties

Versions 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.4, 0.2.5, 0.2.6, 0.2.7, 0.2.8, 0.2.9, 0.2.10, 0.3.0, 0.3.1, 0.3.2, 0.3.3, 0.3.4, 0.3.5, 0.4.0, 0.4.1, 0.4.2, 0.4.4, 0.4.6, 0.4.8, 0.4.10, 0.4.12, 0.4.14, 0.4.16, 0.4.18, 0.4.18, 0.4.20
Change log changelog.md
Dependencies base (>=4 && <5), cmdargs, containers, express (>=1.0.0), leancheck (>=1.0.0) [details]
License BSD-3-Clause
Author Rudy Matela, Colin Runciman
Maintainer Rudy Matela <rudy@matela.com.br>
Category Testing
Home page https://github.com/rudymatela/speculate#readme
Source repo head: git clone https://github.com/rudymatela/speculate
this: git clone https://github.com/rudymatela/speculate(tag v0.4.18)
Uploaded by rudymatela at 2024-02-12T14:11:01Z

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for speculate-0.4.18

[back to package description]

Speculate

Speculate Build Status Speculate on Hackage Speculate on Stackage LTS Speculate on Stackage Nightly

Speculate logo

Speculate automatically discovers laws about Haskell functions. Give Speculate a bunch of Haskell functions and it will discover laws like:

Speculate is similar to, and inspired by, QuickSpec.

Installing Speculate

To install the latest Speculate version from Hackage, just:

$ cabal update
$ cabal install speculate

Pre-requisites are cmdargs, express and leancheck. They should be automatically resolved and installed by Cabal.

Using Speculate

Speculate is used as a library: import it, then call the function speculate with relevant arguments. The following program Speculates about the functions (+) 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)
      ]
  }

when run, it prints the following:

_ :: Int  (holes: Int)
0 :: Int
1 :: Int
(+) :: Int -> Int -> Int
abs :: Int -> Int

    abs (abs x) == abs x
          x + 0 == x
          x + y == y + x
    (x + y) + z == x + (y + z)
abs (x + abs x) == x + abs x
  abs x + abs x == abs (x + x)
abs (1 + abs x) == 1 + abs x

x <= abs x
0 <= abs x
x <= x + 1

Now, if we add <= and < as background constants on args

  , constants =
      [ showConstant (0::Int)
      , showConstant (1::Int)
      , constant "+"   ((+)  :: Int -> Int -> Int)
      , constant "abs" (abs  :: Int -> Int)
      , background
      , constant "<="  ((<=) :: Int -> Int -> Bool)
      , constant "<"   ((<)  :: Int -> Int -> Bool)
      ]

then run again, we get the following as well:

    y <= x ==> abs (x + abs y) == x + abs y
    x <= 0 ==>       x + abs x == 0
abs x <= y ==>     abs (x + y) == x + y
abs y <= x ==>     abs (x + y) == x + y

For more examples, see the eg folder.

(One can use the TypeApplications to simplify the above examples: ((+) @ Int) instead of ((+) :: Int -> Int -> Int)). I have chosen to keep the example Haskell 98 compliant.)

Supported types

Speculate works for virtually any type. However, if you would like to produce equations, comparisons and variables of any given type this type must be respectively an instance of the Eq, Ord, Listable and Name typeclasses.

By default, Speculate will produce equations, comparison and variables to a few types in the Haskell 2010 Language Report. If you would like expand that to more types, you need to pass reified instances to Speculate explicitly by using reifyInstances on instances = of speculate's args like so:

main = speculate args
  { instances = [ reifyInstances (undefined :: <Type1>)
                , reifyInstances (undefined :: <Type2>)
                , reifyInstances (undefined :: <Type3>)
                , ...
                ]
  , constants = ...
  , ...
  }

To use reifyInstances, your type must be an instance of Eq, Ord, Listable and Name.

It is also fine to have only one, two or three of the above instances. In that case, instead of reifyInstances you can use reifyEq, reifyOrd, reifyListable and reifyName accordingly. If you do not provide a Name implementation, your variables will default to being x, y and z. This may cause confusion as you involve more and more types, compare the following two identical equations:

[x,y] `areOwnedBy` z  ==  z `owns` x && z `owns` y
[tckt,tckt1] `areOwnedBy` user  ==  usr `owns` tckt && user `owns tckt1`

The second is clearer. So, I recomment you add a Name instance. It is simple enough.

You also have to do this for any user defined types you are using or even for newtypes.

Speculate comes with a few examples illustrating the use of reifyInstances: on the eg folder: eg/algebraic-graphs.hs, eg/binarytree0.hs, eg/binarytree.hs, eg/colour.hs, eg/digraphs.hs, eg/fun.hs, eg/monad.hs, eg/pretty-compact.hs, eg/pretty.hs, eg/regexes.hs, eg/sets.hs, eg/speculate-reason.hs, eg/string.hs, eg/tauts.hs, eg/tuples.hs, eg/zip.hs.

Not having the reified instances for a given type will cause the following warnings to be printed:

Warning: no Listable instance for <YourTypeHere>, variables of this type will not be considered
Warning: no Listable instance for <YourTypeHere>, variables of this type will not be considered
Warning: no Eq instance for <YourTypeHere>, equations of this type will not be considered
Warning: no Eq instance for <YourTypeHere>, equations of this type will not be considered
Warning: no Ord instance for <YourTypeHere>, inequations of this type will not be considered
Warning: no Ord instance for <YourTypeHere>, inequations of this type will not be considered

You can silence the above warnings by following the instructions above. However, it may be the case that you don't want variables, equations or comparisons for a given type. If that is so, you can ignore these warnings.

Similarities and Differences to QuickSpec

Speculate is inspired by QuickSpec. Like QuickSpec, Speculate uses testing to speculate equational laws about given Haskell functions. There are some differences:

More documentation

For more examples, see the eg and bench folders.

Speculate has been subject to a paper, see the Speculate Paper on Haskell Symposium 2017. Speculate is also subject to a chapter in a PhD Thesis (2017).