summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGergo ERDI <gergo@erdi.hu>2022-05-16 14:02:20 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-10-17 19:20:04 -0400
commit8c72411d9504963069fb1ae736a2470cb9ae1250 (patch)
tree7b3232544dcda6a7c94c423581fd44529768b258
parentc1e5719aa500cb9e0f2549eb9b9e2255038ac35d (diff)
downloadhaskell-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.hs24
-rw-r--r--libraries/base/changelog.md3
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*