<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/quickcheck-property-uncategorised-bill-5otz7lkcv" -->

---
title: QuickCheck property: Uncategorised bill | daily.dev
description: This post starts a Haskell budgeting kata using QuickCheck property-based tests instead of example-based ones. It defines a polymorphic Budget type and an...
canonical: https://daily.dev/posts/quickcheck-property-uncategorised-bill-5otz7lkcv
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: QuickCheck property: Uncategorised bill | daily.dev
og:description: This post starts a Haskell budgeting kata using QuickCheck property-based tests instead of example-based ones. It defines a polymorphic Budget type and an...
og:url: https://daily.dev/posts/quickcheck-property-uncategorised-bill-5otz7lkcv
og:image: https://api.daily.dev/og/posts/5OtZ7lKcV.png
og:image:alt: QuickCheck property: Uncategorised bill
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# QuickCheck property: Uncategorised bill

**[ploeh blog](https://daily.dev/sources/ploeh)** · 11 min read · 0 upvotes · 0 comments

## Summary

This post starts a Haskell budgeting kata using QuickCheck property-based tests instead of example-based ones. It defines a polymorphic Budget type and an Item/Bill structure, with category identifiers left generic so tests can pick a small, shrinkable set of values instead of QuickCheck's infinite String generator. A first property, 'Uncategorized bill is only determined by its cost', checks that a bill without categories is affordable only when its total cost is under the limit. The simplest implementation that passes is canAfford budget bill = billCost bill <= totalLimit budget. The author also shows and rejects an earlier two-test, example-based alternative as duplicative of this single property.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://blog.ploeh.dk/2026/10/26/quickcheck-property-uncategorised-bill>

## Questions this post answers

### Why does QuickCheck generating random String values cause problems for property-based tests that need duplicate category identifiers?

QuickCheck picks strings from an infinite set, including values like 'a', 'fê', and unprintable characters, so the probability of generating two identical values in the same property is very small. Some properties need duplicate identifiers to exercise overlapping categories, so a parametric type lets you substitute a smaller, controllable set of values instead.

_daily.dev surfaces Haskell and QuickCheck write-ups for developers tuning their property-based test generators._

### How do you define a custom Arbitrary instance with shrinking support in Haskell QuickCheck for a record with multiple fields?

Wrap the type in a newtype like AnyItem, define arbitrary using do-notation to compose generators for each field (such as Positive Int for cost and count), and implement shrink by delegating to the shrinkers of the underlying tuple, like shrink (Positive cost, Positive count, categories), then rewrapping the results. This avoids orphan instances and keeps shrinking working for all fields.

_Developers writing QuickCheck generators can find practical shrinking patterns like this on daily.dev._

### What is the simplest Haskell implementation of a canAfford function that checks if a bill fits within a budget's total limit?

canAfford budget bill = billCost bill <= totalLimit budget, where billCost sums each item's cost multiplied by its count across the bill. This passes a QuickCheck property stating that an uncategorized bill's affordability depends only on whether its total cost is less than or equal to the budget's total limit.

_daily.dev helps developers compare implementation approaches like this while building out TDD katas._

## Similar posts on daily.dev

- [Properties for a budgeting exercise](https://daily.dev/posts/properties-for-a-budgeting-exercise-xtfg44ijq) · ploeh blog · 0 upvotes · 0 comments
- ["Five-Point Haskell": Unconditional Election \(via Parametricity\)](https://daily.dev/posts/five-point-haskell-unconditional-election-via-parametricity--r0wfzd72l) · Planet Haskell · 0 upvotes · 0 comments
- [What is a property?](https://daily.dev/posts/what-is-a-property--ngbye7wme) · Hacker News · 0 upvotes · 0 comments
- [Issue 534](https://daily.dev/posts/issue-534-rpp60utgy) · Haskell Weekly · 0 upvotes · 0 comments
- [Code Contracts: Halfway Between Unit Testing And Formal Verification](https://daily.dev/posts/code-contracts-halfway-between-unit-testing-and-formal-verification-yfxhh0jes) · marmelab · 2 upvotes · 0 comments

---

Tags: [#testing](https://daily.dev/tags/testing), [#haskell](https://daily.dev/tags/haskell), [#tdd](https://daily.dev/tags/tdd)

[View this post on daily.dev](https://daily.dev/posts/quickcheck-property-uncategorised-bill-5otz7lkcv)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"QuickCheck property: Uncategorised bill","url":"https://daily.dev/posts/quickcheck-property-uncategorised-bill-5otz7lkcv","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/quickcheck-property-uncategorised-bill-5otz7lkcv"},"datePublished":"2026-10-26T06:53:00.331Z","dateModified":"2026-10-26T07:04:28.669Z","description":"This post starts a Haskell budgeting kata using QuickCheck property-based tests instead of example-based ones. It defines a polymorphic Budget type and an...","image":"https://media.daily.dev/image/upload/s--P4t4XyoV--/f_auto/v1722860399/public/Placeholder%2001","thumbnailUrl":"https://media.daily.dev/image/upload/s--P4t4XyoV--/f_auto/v1722860399/public/Placeholder%2001","isAccessibleForFree":true,"articleSection":"ploeh blog","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"ploeh blog","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/0645fe7a0b9f40ba9ef17f7a7b49e893","url":"https://daily.dev/sources/ploeh"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/quickcheck-property-uncategorised-bill-5otz7lkcv","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"testing,haskell,tdd","timeRequired":"PT11M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"ploeh blog","item":"https://daily.dev/sources/ploeh"},{"@type":"ListItem","position":3,"name":"QuickCheck property: Uncategorised bill"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/quickcheck-property-uncategorised-bill-5otz7lkcv#faq","mainEntity":[{"@type":"Question","name":"Why does QuickCheck generating random String values cause problems for property-based tests that need duplicate category identifiers?","acceptedAnswer":{"@type":"Answer","text":"QuickCheck picks strings from an infinite set, including values like 'a', 'fê', and unprintable characters, so the probability of generating two identical values in the same property is very small. Some properties need duplicate identifiers to exercise overlapping categories, so a parametric type lets you substitute a smaller, controllable set of values instead. daily.dev surfaces Haskell and QuickCheck write-ups for developers tuning their property-based test generators."}},{"@type":"Question","name":"How do you define a custom Arbitrary instance with shrinking support in Haskell QuickCheck for a record with multiple fields?","acceptedAnswer":{"@type":"Answer","text":"Wrap the type in a newtype like AnyItem, define arbitrary using do-notation to compose generators for each field (such as Positive Int for cost and count), and implement shrink by delegating to the shrinkers of the underlying tuple, like shrink (Positive cost, Positive count, categories), then rewrapping the results. This avoids orphan instances and keeps shrinking working for all fields. Developers writing QuickCheck generators can find practical shrinking patterns like this on daily.dev."}},{"@type":"Question","name":"What is the simplest Haskell implementation of a canAfford function that checks if a bill fits within a budget's total limit?","acceptedAnswer":{"@type":"Answer","text":"canAfford budget bill = billCost bill \u003c= totalLimit budget, where billCost sums each item's cost multiplied by its count across the bill. This passes a QuickCheck property stating that an uncategorized bill's affordability depends only on whether its total cost is less than or equal to the budget's total limit. daily.dev helps developers compare implementation approaches like this while building out TDD katas."}}]}
```

