Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IntegerInterval: add memberCount #44

Merged
merged 1 commit into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/Data/IntegerInterval.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ module Data.IntegerInterval
, lowerBound'
, upperBound'
, width
, memberCount

-- * Universal comparison operators
, (<!), (<=!), (==!), (>=!), (>!), (/=!)
Expand Down Expand Up @@ -309,6 +310,17 @@ width x
(Finite lb, Finite ub) -> ub - lb
_ -> error "Data.IntegerInterval.width: unbounded interval"

-- | How many integers lie within the (bounded) interval.
-- Equal to @Just (width + 1)@ for non-empty, bounded intervals.
-- The @memberCount@ of an unbounded interval is @Nothing@.
memberCount :: IntegerInterval -> Maybe Integer
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As usual, the shorter PR the longer bikeshedding :)

I wonder if Maybe Natural would be a better return type. Two benefits:

  • It's the smallest possible set of values, making memberCount surjective.
  • It's more distinguishing, e. g., one cannot replace memberCount with pickup.
    An obvious penalty:
  • Users are likely to need more fromIntegral / toInteger.

I'm split. @ncfavier what do you think? Let's do what you prefer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this were Agda I would definitely insist on returning Maybe ℕ, but in a low-level language like Haskell I don't think it's worth the trouble. You don't pattern match on Integer.

memberCount x
| null x = Just 0
| otherwise =
case (lowerBound x, upperBound x) of
(Finite lb, Finite ub) -> Just (ub - lb + 1)
_ -> Nothing

-- | pick up an element from the interval if the interval is not empty.
pickup :: IntegerInterval -> Maybe Integer
pickup x =
Expand Down
14 changes: 14 additions & 0 deletions test/TestIntegerInterval.hs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,20 @@ prop_width_singleton =
forAll arbitrary $ \x ->
IntegerInterval.width (IntegerInterval.singleton x) == 0

{--------------------------------------------------------------------
memberCount
--------------------------------------------------------------------}

case_memberCount_null =
IntegerInterval.memberCount IntegerInterval.empty @?= Just 0

case_memberCount_positive =
IntegerInterval.memberCount (0 <=..< 10) @?= Just 10

prop_memberCount_singleton =
forAll arbitrary $ \x ->
IntegerInterval.memberCount (IntegerInterval.singleton x) == Just 1

{--------------------------------------------------------------------
map
--------------------------------------------------------------------}
Expand Down
Loading