{"id":20606134,"url":"https://github.com/rudymatela/speculate","last_synced_at":"2025-04-15T02:43:00.791Z","repository":{"id":56878653,"uuid":"76549478","full_name":"rudymatela/speculate","owner":"rudymatela","description":"Speculate laws about Haskell functions","archived":false,"fork":false,"pushed_at":"2024-02-13T12:37:55.000Z","size":1103,"stargazers_count":30,"open_issues_count":3,"forks_count":0,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-04-26T01:02:15.009Z","etag":null,"topics":["enumerative-testing","haskell","leancheck","property-based-testing","property-discovery","property-testing","testing","theory-exploration"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rudymatela.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-12-15T10:21:22.000Z","updated_at":"2022-12-03T23:09:17.000Z","dependencies_parsed_at":"2024-11-16T09:32:45.371Z","dependency_job_id":"ffd18a29-cd18-4cb7-83d2-9ec100f47e5e","html_url":"https://github.com/rudymatela/speculate","commit_stats":{"total_commits":1003,"total_committers":1,"mean_commits":1003.0,"dds":0.0,"last_synced_commit":"84abba68a27158ad8b58c606bd8c9d574a70cce0"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudymatela%2Fspeculate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudymatela%2Fspeculate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudymatela%2Fspeculate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudymatela%2Fspeculate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rudymatela","download_url":"https://codeload.github.com/rudymatela/speculate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248997049,"owners_count":21195785,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["enumerative-testing","haskell","leancheck","property-based-testing","property-discovery","property-testing","testing","theory-exploration"],"created_at":"2024-11-16T09:32:39.575Z","updated_at":"2025-04-15T02:43:00.773Z","avatar_url":"https://github.com/rudymatela.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"Speculate\n=========\n\n[![Speculate Build Status][build-status]][build-log]\n[![Speculate on Hackage][hackage-version]][speculate-on-hackage]\n[![Speculate on Stackage LTS][stackage-lts-badge]][speculate-on-stackage-lts]\n[![Speculate on Stackage Nightly][stackage-nightly-badge]][speculate-on-stackage-nightly]\n\n![Speculate logo][speculate-logo]\n\nSpeculate automatically discovers laws about [Haskell] functions.\nGive Speculate a bunch of Haskell functions and it will discover laws like:\n\n  * equations, such as `id x == x`;\n  * relations of order, such as `0 \u003c= x * x`;\n  * conditional equations, such as `x \u003c= 0  ==\u003e  x + abs x == 0`.\n\nSpeculate is similar to, and inspired by, [QuickSpec].\n\n\nInstalling Speculate\n--------------------\n\nTo install the [latest Speculate version from Hackage], just:\n\n\t$ cabal update\n\t$ cabal install speculate\n\nPre-requisites are [cmdargs], [express] and [leancheck].\nThey should be automatically resolved and installed by [Cabal].\n\n\nUsing Speculate\n---------------\n\nSpeculate is used as a library: import it, then call the function [`speculate`]\nwith relevant arguments.  The following program Speculates about the\nfunctions [`(+)`] and [`abs`]:\n\n\timport Test.Speculate\n\n\tmain :: IO ()\n\tmain = speculate args\n\t  { constants =\n\t      [ showConstant (0::Int)\n\t      , showConstant (1::Int)\n\t      , constant \"+\"   ((+)  :: Int -\u003e Int -\u003e Int)\n\t      , constant \"abs\" (abs  :: Int -\u003e Int)\n\t      ]\n\t  }\n\nwhen run, it prints the following:\n\n\t_ :: Int  (holes: Int)\n\t0 :: Int\n\t1 :: Int\n\t(+) :: Int -\u003e Int -\u003e Int\n\tabs :: Int -\u003e Int\n\n\t    abs (abs x) == abs x\n\t          x + 0 == x\n\t          x + y == y + x\n\t    (x + y) + z == x + (y + z)\n\tabs (x + abs x) == x + abs x\n\t  abs x + abs x == abs (x + x)\n\tabs (1 + abs x) == 1 + abs x\n\n\tx \u003c= abs x\n\t0 \u003c= abs x\n\tx \u003c= x + 1\n\n\nNow, if we add [`\u003c=`] and [`\u003c`] as background constants on [`args`]\n\n\t  , constants =\n\t      [ showConstant (0::Int)\n\t      , showConstant (1::Int)\n\t      , constant \"+\"   ((+)  :: Int -\u003e Int -\u003e Int)\n\t      , constant \"abs\" (abs  :: Int -\u003e Int)\n\t      , background\n\t      , constant \"\u003c=\"  ((\u003c=) :: Int -\u003e Int -\u003e Bool)\n\t      , constant \"\u003c\"   ((\u003c)  :: Int -\u003e Int -\u003e Bool)\n\t      ]\n\nthen run again, we get the following as well:\n\n\t    y \u003c= x ==\u003e abs (x + abs y) == x + abs y\n\t    x \u003c= 0 ==\u003e       x + abs x == 0\n\tabs x \u003c= y ==\u003e     abs (x + y) == x + y\n\tabs y \u003c= x ==\u003e     abs (x + y) == x + y\n\nFor more examples, see the [eg](eg) folder.\n\n(One can use the [TypeApplications] to simplify the above examples:\n`((+) @ Int)` instead of `((+) :: Int -\u003e Int -\u003e Int))`.\nI have chosen to keep the example [Haskell 98] compliant.)\n\n\nSupported types\n---------------\n\nSpeculate works for virtually any type.\nHowever,\nif you would like to produce equations,\ncomparisons and variables of any given type\nthis type must be respectively\nan instance of the [`Eq`], [`Ord`], [`Listable`] and [`Name`] typeclasses.\n\nBy default,\nSpeculate will produce equations, comparison and variables\nto [a few types](https://github.com/rudymatela/speculate/blob/master/src/Test/Speculate/Expr/Instance.hs#L110-L151)\nin the [Haskell 2010 Language Report].\nIf you would like expand that to more types,\nyou need to pass reified instances to Speculate explicitly by\nusing [`reifyInstances`] on [`instances =`] of [`speculate`]'s [`args`] like so:\n\n\tmain = speculate args\n      { instances = [ reifyInstances (undefined :: \u003cType1\u003e)\n                    , reifyInstances (undefined :: \u003cType2\u003e)\n                    , reifyInstances (undefined :: \u003cType3\u003e)\n\t                , ...\n\t                ]\n      , constants = ...\n\t  , ...\n\t  }\n\nTo use [`reifyInstances`],\nyour type must be an instance of\n[`Eq`], [`Ord`], [`Listable`] and [`Name`].\n\n* [`Eq`]  is needed for equations between values of the type;\n\n* [`Ord`] is needed for comparisons between values of the type;\n\n* [`Listable`] is needed for involving variables of the type.\n  This is needed in order for Speculate to be able\n  to generate values of your type to replace any variables.\n  [LeanCheck] comes with [`Listable`] instances\n  for virtually all types in the [Haskell 2010 Language Report].\n\n* [`Name`] is needed for cosmetic puposes:\n  if there are any variables of your type,\n  [`Name`] allows you to tell Speculate how to call your variables.\n  For example, if you have an `User` type, you can define your name instance as:\n\n\t\tinstance Name (User) where\n\t\t\tname u  =  \"usr\"\n\n  This way, variables of your `User` type will be called:\n  `usr`, `usr1`, `usr2`, `usr3`, etc.\n\nIt is also fine to have only one, two or three of the above instances.\nIn that case, instead of [`reifyInstances`]\nyou can use [`reifyEq`], [`reifyOrd`], [`reifyListable`] and [`reifyName`] accordingly.\nIf you do not provide a [`Name`] implementation,\nyour variables will default to being `x`, `y` and `z`.\nThis may cause confusion as you involve more and more types,\ncompare the following two identical equations:\n\n\t[x,y] `areOwnedBy` z  ==  z `owns` x \u0026\u0026 z `owns` y\n\t[tckt,tckt1] `areOwnedBy` user  ==  usr `owns` tckt \u0026\u0026 user `owns tckt1`\n\nThe second is clearer.\nSo, I recomment you add a [`Name`] instance.\nIt is simple enough.\n\nYou also have to do this for any user defined types you are using\nor even for newtypes.\n\nSpeculate comes with a few examples illustrating the use of [`reifyInstances`]:\non the [eg](eg) folder:\n[eg/algebraic-graphs.hs](eg/algebraic-graphs.hs),\n[eg/binarytree0.hs](eg/binarytree0.hs),\n[eg/binarytree.hs](eg/binarytree.hs),\n[eg/colour.hs](eg/colour.hs),\n[eg/digraphs.hs](eg/digraphs.hs),\n[eg/fun.hs](eg/fun.hs),\n[eg/monad.hs](eg/monad.hs),\n[eg/pretty-compact.hs](eg/pretty-compact.hs),\n[eg/pretty.hs](eg/pretty.hs),\n[eg/regexes.hs](eg/regexes.hs),\n[eg/sets.hs](eg/sets.hs),\n[eg/speculate-reason.hs](eg/speculate-reason.hs),\n[eg/string.hs](eg/string.hs),\n[eg/tauts.hs](eg/tauts.hs),\n[eg/tuples.hs](eg/tuples.hs),\n[eg/zip.hs](eg/zip.hs).\n\nNot having the reified instances for a given type will cause the following warnings to be printed:\n\n\tWarning: no Listable instance for \u003cYourTypeHere\u003e, variables of this type will not be considered\n\tWarning: no Listable instance for \u003cYourTypeHere\u003e, variables of this type will not be considered\n\tWarning: no Eq instance for \u003cYourTypeHere\u003e, equations of this type will not be considered\n\tWarning: no Eq instance for \u003cYourTypeHere\u003e, equations of this type will not be considered\n\tWarning: no Ord instance for \u003cYourTypeHere\u003e, inequations of this type will not be considered\n\tWarning: no Ord instance for \u003cYourTypeHere\u003e, inequations of this type will not be considered\n\nYou can silence the above warnings by following the instructions above.\nHowever, it may be the case that you don't want variables, equations or comparisons for a given type.\nIf that is so, you can ignore these warnings.\n\n\nSimilarities and Differences to QuickSpec\n-----------------------------------------\n\nSpeculate is inspired by [QuickSpec].\nLike QuickSpec, Speculate uses testing to speculate equational laws about given\nHaskell functions.  There are some differences:\n\n* Speculate tests enumeratively using [LeanCheck],\n  QuickSpec tests randomly using [QuickCheck];\n* Speculate is able to report comparisons directly;\n* QuickSpec allows polymorphism, Speculate does not;\n* For most examples,\n  Speculate runs slower than QuickSpec 2\n  but faster than QuickSpec 1.\n\n\nMore documentation\n------------------\n\nFor more examples, see the [eg](eg) and [bench](bench) folders.\n\nSpeculate has been subject to a paper, see the\n[Speculate Paper on Haskell Symposium 2017](https://matela.com.br/speculate.pdf).\nSpeculate is also subject to a chapter in a [PhD Thesis (2017)].\n\n[leancheck]: https://hackage.haskell.org/package/leancheck\n[LeanCheck]: https://hackage.haskell.org/package/leancheck\n[express]:   https://hackage.haskell.org/package/express\n[QuickSpec]: https://github.com/nick8325/quickspec\n[QuickCheck]: https://hackage.haskell.org/package/QuickCheck\n[cmdargs]: https://hackage.haskell.org/package/cmdargs\n\n[Cabal]:   https://www.haskell.org/cabal\n[Haskell]: https://www.haskell.org/\n\n[PhD Thesis (2017)]: https://matela.com.br/thesis-rudy.pdf\n\n[`speculate`]:      https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#v:speculate\n[`constant`]:       https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#v:constant\n[`args`]:           https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#v:args\n[`Args`]:           https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#t:Args\n[`instances =`]:    https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#t:Args\n\n[`reifyInstances`]: https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#v:reifyInstances\n[`reifyEq`]:        https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#v:reifyEq\n[`reifyOrd`]:       https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#v:reifyOrd\n[`reifyEqOrd`]:     https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#v:reifyEqOrd\n[`reifyListable`]:  https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#v:reifyListable\n[`reifyName`]:      https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#v:reifyName\n\n[`Eq`]:             https://hackage.haskell.org/package/base/docs/Prelude.html#t:Eq\n[`Ord`]:            https://hackage.haskell.org/package/base/docs/Prelude.html#t:Ord\n[`Listable`]:       https://hackage.haskell.org/package/leancheck/docs/Test-LeanCheck.html#t:Listable\n[`Name`]:           https://hackage.haskell.org/package/speculate/docs/Test-Speculate.html#t:Name\n\n[`(+)`]:       https://hackage.haskell.org/package/base/docs/Prelude.html#v:-43-\n[`abs`]:       https://hackage.haskell.org/package/base/docs/Prelude.html#v:abs\n[`\u003c=`]:        https://hackage.haskell.org/package/base/docs/Prelude.html#v:-60--61-\n[`\u003c`]:         https://hackage.haskell.org/package/base/docs/Prelude.html#v:-60-\n\n[Haskell 2010 Language Report]:          https://www.haskell.org/onlinereport/haskell2010/\n[Haskell 2010]:                          https://www.haskell.org/onlinereport/haskell2010/\n[Haskell 98]:                            https://www.haskell.org/onlinereport/\n[TypeApplications]:                      https://gitlab.haskell.org/ghc/ghc/-/wikis/type-application\n\n[speculate-logo]: https://github.com/rudymatela/speculate/raw/master/doc/speculate.svg?sanitize=true\n\n[build-log]:    https://github.com/rudymatela/speculate/actions/workflows/build.yml\n[build-status]: https://github.com/rudymatela/speculate/actions/workflows/build.yml/badge.svg\n[hackage-version]: https://img.shields.io/hackage/v/speculate.svg\n[latest Speculate version from Hackage]: https://hackage.haskell.org/package/speculate\n[speculate-on-hackage]:                  https://hackage.haskell.org/package/speculate\n[stackage-lts-badge]:            https://stackage.org/package/speculate/badge/lts\n[stackage-nightly-badge]:        https://stackage.org/package/speculate/badge/nightly\n[speculate-on-stackage]:         https://stackage.org/package/speculate\n[speculate-on-stackage-lts]:     https://stackage.org/lts/package/speculate\n[speculate-on-stackage-nightly]: https://stackage.org/nightly/package/speculate\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frudymatela%2Fspeculate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frudymatela%2Fspeculate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frudymatela%2Fspeculate/lists"}