{"id":20481901,"url":"https://github.com/typeable/generic-arbitrary","last_synced_at":"2025-04-13T14:11:15.357Z","repository":{"id":25448310,"uuid":"83994410","full_name":"typeable/generic-arbitrary","owner":"typeable","description":"Generic method implementations for Arbitrary","archived":false,"fork":false,"pushed_at":"2024-01-16T07:21:48.000Z","size":70,"stargazers_count":7,"open_issues_count":1,"forks_count":7,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-04-25T23:43:55.570Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/typeable.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":"2017-03-05T19:00:24.000Z","updated_at":"2021-12-14T21:04:40.000Z","dependencies_parsed_at":"2024-11-15T16:20:28.044Z","dependency_job_id":null,"html_url":"https://github.com/typeable/generic-arbitrary","commit_stats":{"total_commits":59,"total_committers":7,"mean_commits":8.428571428571429,"dds":"0.27118644067796616","last_synced_commit":"ccf2c0decadd41e04aed05c41fb8ba7a35f8755f"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeable%2Fgeneric-arbitrary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeable%2Fgeneric-arbitrary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeable%2Fgeneric-arbitrary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeable%2Fgeneric-arbitrary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typeable","download_url":"https://codeload.github.com/typeable/generic-arbitrary/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248724629,"owners_count":21151561,"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":[],"created_at":"2024-11-15T16:10:13.936Z","updated_at":"2025-04-13T14:11:15.322Z","avatar_url":"https://github.com/typeable.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# generic-arbitrary\n\n[![Haskell-CI](https://github.com/typeable/generic-arbitrary/actions/workflows/haskell-ci.yml/badge.svg)](https://github.com/typeable/generic-arbitrary/actions/workflows/haskell-ci.yml)\n\n# What?\n\nPackage for deriving `Arbitrary` via `Generic`.\n\n``` haskell\nimport           GHC.Generics                      (Generic)\nimport           Test.QuickCheck\nimport           Test.QuickCheck.Arbitrary.Generic\n\ndata Expr\n  = Lit Int\n  | Add Expr Expr\n  | Mul Expr Expr\n  deriving (Eq, Show, Generic)\n  deriving Arbitrary via (GenericArbitrary Expr)\n```\n\nOlder versions of this package had a problem with hanging `arbitrary`\nmethod. Since `1.0.0` this problem almost solved.\n\nFor `QuickCheck` older than `2.14.0` the `GenericArbitrary` is not available, so\nyou will need to write instances more verbosely\n\n``` haskell\ndata Expr\n  = Lit Int\n  | Add Expr Expr\n  | Mul Expr Expr\n  deriving (Eq, Show, Generic)\n\ninstance Arbitrary Expr where\n  arbitrary = genericArbitrary\n  shrink = genericShrink\n```\n\nWhich is generally the same.\n\n# Infinite terms problem\n\nThe `generic-arbitrary` can partially handle the problem with recursive\ntypes. Assume the type `R`\n\n``` haskell\ndata R = R R\n  deriving Generic\n```\n\nthere is no instance\n\n``` haskell\ninstance Arbitrary R where\n  arbitrary = genericArbitrary\n  shrink = genericShrink\n```\n\nIf you try to compile this you will get a type level error\n\n\u003e    • R refers to itself in all constructors\n\nWhich means that there is no finite term for `R` because it is recursive in all\nit's constructors. But, if you correct the definition of `R` like this.\n\n``` haskell\ndata R = R R | F\n  deriving Generic\n```\n\nThen it will compile. And the `arbitrary` generated will not hang forever,\nbecause it respects the `size` parameter.\n\n## Limitation\n\nThere is a limitation of recursion detection:\n\n``` haskell\ndata R1 = R1 R2\n  deriving (Eq, Ord, Show, Generic)\n  deriving anyclass NFData\n  deriving Arbitrary via (GenericArbitrary R1)\n\ndata R2 = R2 R1\n  deriving (Eq, Ord, Show, Generic)\n  deriving anyclass NFData\n  deriving Arbitrary via (GenericArbitrary R2)\n```\n\nThis code will compile and the `arbitrary` generated will always hang. Yes,\nthere is a problem with mutually recursive types.\n\n# Type parameters\n\nNow let's see an example of datatype with parameters\n\n``` haskell\ndata A a = A a\n  deriving (Eq, Ord, Show)\n  deriving anyclass NFData\n  deriving (Generic)\n\ninstance (Arbitrary a) =\u003e Arbitrary (A a) where\n  arbitrary = genericArbitrary\n  shrink = genericShrink\n```\n\nIt should work from first glance, but when compile it will throw an error:\n\n```\n• Could not deduce (Test.QuickCheck.Arbitrary.Generic.GArbitrary\n                          (A a)\n                          (GHC.Generics.D1\n                             ('GHC.Generics.MetaData \"A\" \"ParametersTest\" \"main\" 'False)\n                             (GHC.Generics.C1\n                                ('GHC.Generics.MetaCons \"A\" 'GHC.Generics.PrefixI 'False)\n                                (GHC.Generics.S1\n                                   ('GHC.Generics.MetaSel\n                                      'Nothing\n                                      'GHC.Generics.NoSourceUnpackedness\n                                      'GHC.Generics.NoSourceStrictness\n                                      'GHC.Generics.DecidedLazy)\n                                   (GHC.Generics.Rec0 a))))\n                          (TypesDiffer (A a) a))\n        arising from a use of ‘genericArbitrary’\n```\n\nHere the `TypesDiffer` is a type familty dealing with recursive types and\nhelping us to eliminate inproper instances. To convince the compiller, that the\n`a` parameter is not an `A a` we must fix the instance with additional\nconstraint `Arg (A a) a`\n\n``` haskell\ninstance (Arg (A a) a, Arbitrary a) =\u003e Arbitrary (A a) where\n  arbitrary = genericArbitrary\n  shrink = genericShrink\n```\n\nNow everything compiles and works as expected.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypeable%2Fgeneric-arbitrary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypeable%2Fgeneric-arbitrary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypeable%2Fgeneric-arbitrary/lists"}