summaryrefslogtreecommitdiff
path: root/libraries/base/Data/Type/Ord.hs
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/base/Data/Type/Ord.hs')
-rw-r--r--libraries/base/Data/Type/Ord.hs125
1 files changed, 125 insertions, 0 deletions
diff --git a/libraries/base/Data/Type/Ord.hs b/libraries/base/Data/Type/Ord.hs
new file mode 100644
index 0000000000..d882a82a61
--- /dev/null
+++ b/libraries/base/Data/Type/Ord.hs
@@ -0,0 +1,125 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE Safe #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE StandaloneKindSignatures #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module : Data.Type.Ord
+-- License : BSD-style (see the LICENSE file in the distribution)
+--
+-- Maintainer : libraries@haskell.org
+-- Stability : experimental
+-- Portability : not portable
+--
+-- Basic operations on type-level Orderings.
+--
+-- @since 4.16.0.0
+-----------------------------------------------------------------------------
+
+module Data.Type.Ord (
+ Compare, OrderingI(..)
+ , type (<=), type (<=?)
+ , type (>=), type (>=?)
+ , type (>), type (>?)
+ , type (<), type (<?)
+ , Max, Min
+ , OrdCond
+ ) where
+
+import GHC.Show(Show(..))
+import GHC.TypeLits.Internal
+import GHC.TypeNats.Internal
+import Data.Bool
+import Data.Char(Char)
+import Data.Eq
+import Data.Ord
+
+-- | 'Compare' branches on the kind of its arguments to either compare by
+-- 'Symbol' or 'Nat'.
+-- @since 4.16.0.0
+type Compare :: k -> k -> Ordering
+type family Compare a b
+
+type instance Compare (a :: Natural) b = CmpNat a b
+type instance Compare (a :: Symbol) b = CmpSymbol a b
+type instance Compare (a :: Char) b = CmpChar a b
+
+-- | Ordering data type for type literals that provides proof of their ordering.
+-- @since 4.16.0.0
+data OrderingI a b where
+ LTI :: Compare a b ~ 'LT => OrderingI a b
+ EQI :: Compare a a ~ 'EQ => OrderingI a a
+ GTI :: Compare a b ~ 'GT => OrderingI a b
+
+deriving instance Show (OrderingI a b)
+deriving instance Eq (OrderingI a b)
+
+
+infix 4 <=?, <=, >=?, >=, <?, <, >?, >
+
+-- | Comparison (<=) of comparable types, as a constraint.
+-- @since 4.16.0.0
+type x <= y = (x <=? y) ~ 'True
+
+-- | Comparison (>=) of comparable types, as a constraint.
+-- @since 4.16.0.0
+type x >= y = (x >=? y) ~ 'True
+
+-- | Comparison (<) of comparable types, as a constraint.
+-- @since 4.16.0.0
+type x < y = (x >? y) ~ 'True
+
+-- | Comparison (>) of comparable types, as a constraint.
+-- @since 4.16.0.0
+type x > y = (x >? y) ~ 'True
+
+
+-- | Comparison (<=) of comparable types, as a function.
+-- @since 4.16.0.0
+type (<=?) :: k -> k -> Bool
+type m <=? n = OrdCond (Compare m n) 'True 'True 'False
+
+-- | Comparison (>=) of comparable types, as a function.
+-- @since 4.16.0.0
+type (>=?) :: k -> k -> Bool
+type m >=? n = OrdCond (Compare m n) 'False 'True 'True
+
+-- | Comparison (<) of comparable types, as a function.
+-- @since 4.16.0.0
+type (<?) :: k -> k -> Bool
+type m <? n = OrdCond (Compare m n) 'True 'False 'False
+
+-- | Comparison (>) of comparable types, as a function.
+-- @since 4.16.0.0
+type (>?) :: k -> k -> Bool
+type m >? n = OrdCond (Compare m n) 'False 'False 'True
+
+
+-- | Maximum between two comparable types.
+-- @since 4.16.0.0
+type Max :: k -> k -> k
+type Max m n = OrdCond (Compare m n) n n m
+
+-- | Minimum between two comparable types.
+-- @since 4.16.0.0
+type Min :: k -> k -> k
+type Min m n = OrdCond (Compare m n) m m n
+
+
+-- | A case statement on `Ordering`.
+-- `Ordering c l e g` is `l` when `c ~ LT`, `e` when `c ~ EQ`, and `g` when
+-- `c ~ GT`.
+-- @since 4.16.0.0
+type OrdCond :: Ordering -> k -> k -> k -> k
+type family OrdCond o lt eq gt where
+ OrdCond 'LT lt eq gt = lt
+ OrdCond 'EQ lt eq gt = eq
+ OrdCond 'GT lt eq gt = gt