diff options
author | Gergo ERDI <gergo@erdi.hu> | 2022-05-16 14:02:20 +0200 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2022-10-17 19:20:04 -0400 |
commit | 8c72411d9504963069fb1ae736a2470cb9ae1250 (patch) | |
tree | 7b3232544dcda6a7c94c423581fd44529768b258 | |
parent | c1e5719aa500cb9e0f2549eb9b9e2255038ac35d (diff) | |
download | haskell-8c72411d9504963069fb1ae736a2470cb9ae1250.tar.gz |
Add `Enum (Down a)` instance that swaps `succ` and `pred`
See https://github.com/haskell/core-libraries-committee/issues/51 for
discussion. The key points driving the implementation are the following
two ideas:
* For the `Int` type, `comparing (complement @Int)` behaves exactly as
an order-swapping `compare @Int`.
* `enumFrom @(Down a)` can be implemented in terms of `enumFromThen @a`,
if only the corner case of starting at the very end is handled specially
-rw-r--r-- | libraries/base/Data/Ord.hs | 24 | ||||
-rw-r--r-- | libraries/base/changelog.md | 3 |
2 files changed, 25 insertions, 2 deletions
diff --git a/libraries/base/Data/Ord.hs b/libraries/base/Data/Ord.hs index b21acb8e33..779e1b69d0 100644 --- a/libraries/base/Data/Ord.hs +++ b/libraries/base/Data/Ord.hs @@ -24,11 +24,11 @@ module Data.Ord ( clamp, ) where -import Data.Bits (Bits, FiniteBits) +import Data.Bits (Bits, FiniteBits, complement) import Foreign.Storable (Storable) import GHC.Ix (Ix) import GHC.Base -import GHC.Enum (Bounded(..)) +import GHC.Enum (Bounded(..), Enum(..)) import GHC.Float (Floating, RealFloat) import GHC.Num import GHC.Read @@ -146,6 +146,26 @@ instance Bounded a => Bounded (Down a) where minBound = Down maxBound maxBound = Down minBound +-- | Swaps @'succ'@ and @'pred'@ of the underlying type. +-- +-- @since 4.18.0.0 +instance (Enum a, Bounded a, Eq a) => Enum (Down a) where + succ = fmap pred + pred = fmap succ + + -- Here we use the fact that 'comparing (complement @Int)' behaves + -- as an order-swapping `compare @Int`. + fromEnum = complement . fromEnum . getDown + toEnum = Down . toEnum . complement + + enumFrom (Down x) + | x == minBound + = [Down x] -- We can't rely on 'enumFromThen _ (pred @a minBound)` behaving nicely, + -- since 'enumFromThen _' might be strict and 'pred minBound' might throw + | otherwise + = coerce $ enumFromThen x (pred x) + enumFromThen (Down x) (Down y) = coerce $ enumFromThen x y + -- | @since 4.11.0.0 instance Functor Down where fmap = coerce diff --git a/libraries/base/changelog.md b/libraries/base/changelog.md index 8861fbb9cf..d955cd59a4 100644 --- a/libraries/base/changelog.md +++ b/libraries/base/changelog.md @@ -47,6 +47,9 @@ that are used in these methods and provide an API to interact with these types, per [CLC proposal #85](https://github.com/haskell/core-libraries-committee/issues/85). + * The `Enum` instance of `Down a` now enumerates values in the opposite + order as the `Enum a` instance, per + [CLC proposal #51](https://github.com/haskell/core-libraries-committee/issues/51). ## 4.17.0.0 *August 2022* |