some 1.0.4.1 → 1.0.5
raw patch · 6 files changed
+217/−11 lines, 6 filesdep ~basedep ~deepseq
Dependency ranges changed: base, deepseq
Files
- ChangeLog.md +27/−0
- some.cabal +6/−9
- src/Data/EqP.hs +98/−0
- src/Data/OrdP.hs +82/−0
- src/Data/Some/GADT.hs +2/−1
- src/Data/Some/Newtype.hs +2/−1
ChangeLog.md view
@@ -1,3 +1,30 @@+# 1.0.5++- Add EqP and OrdP classes.+ These are strong versions of Eq1 and Ord1, and on the other hand+ weaker versions of `GEq` and `GCompare`.+ They are exactly what's needed for `Eq` and `Ord` instances of `Some`.++ The naming is unfortunate: `GShow` would be better named `ShowP`,+ as it's similar version of `Show1`.++ Note: we could add `ReadP` with `readsPrecP :: Int -> ReadS (t a)` method,+ but it will barely have any instances.+ `GRead` is different, as it can reify the type index for many types,+ e.g. for the singletons.++ In some future there will be major version of `some` with following+ breaking changes:+ - `EqP` and `OrdP` will become superclasses of `GEq` and `GCompare`+ - `Eq (Some t)` will require `EqP t`, similarly for `Ord` and `OrdP`.+ - `GShow` will get `forall a. Show (f a)` superclass. (This will cause removal of `Product` and `Sum` instances for `base <4.18`).++ To ease future transition you may+ - Define `EqP` and `OrdP` instances for your types.+ The `defaultEq` and `defaultCompare` methods can be used to define+ `eqp` and `comparep` from `GEq` and `GCompare` instances respectively.+ - Move to use `GHC.Generics.:*:` and `:+:` instead of `Data.Functor.Product` and `Sum`, as these have better `Eq` and `Ord` instances.+ # 1.0.4.1 - Drop support for GHC before 8.6
some.cabal view
@@ -1,5 +1,5 @@ name: some-version: 1.0.4.1+version: 1.0.5 cabal-version: >=1.10 build-type: Simple author:@@ -24,12 +24,7 @@ If you are unsure which variant to use, use the one in "Data.Some" module. tested-with:- GHC ==8.6.5- || ==8.8.4- || ==8.10.4- || ==9.0.2- || ==9.2.4- || ==9.4.2+ GHC ==8.6.5 || ==8.8.4 || ==8.10.4 || ==9.0.2 || ==9.2.7|| ==9.4.4 || ==9.6.1 extra-source-files: ChangeLog.md @@ -42,7 +37,7 @@ source-repository head type: git- location: git://github.com/haskellari/some.git+ location: https://github.com/haskellari/some.git subdir: some library@@ -55,16 +50,18 @@ -- main module exposed-modules: Data.Some exposed-modules:+ Data.EqP Data.GADT.Compare Data.GADT.DeepSeq Data.GADT.Show+ Data.OrdP Data.Some.Church Data.Some.GADT Data.Some.Newtype other-modules: Data.GADT.Internal build-depends:- base >=4.12 && <4.18+ base >=4.12 && <4.19 , deepseq >=1.4.4.0 && <1.5 if impl(ghc >=9.0)
+ src/Data/EqP.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE Safe #-}+{-# LANGUAGE TypeOperators #-}+#if __GLASGOW_HASKELL__ >= 810+{-# LANGUAGE StandaloneKindSignatures #-}+#endif+module Data.EqP (+ EqP (..),+) where++import Control.Applicative (Const (..))+import Data.Kind (Type)+import Data.Proxy (Proxy (..))+import Data.Type.Equality ((:~:) (..), (:~~:) (..))+import GHC.Generics ((:*:) (..), (:+:) (..))+import System.Mem.StableName (StableName, eqStableName)++#if MIN_VERSION_base(4,18,0)+import Data.Functor.Product (Product (..))+import Data.Functor.Sum (Sum (..))+#endif++import qualified Type.Reflection as TR++#if __GLASGOW_HASKELL__ >= 810+import Data.Kind (Constraint)+#endif++-- | Heterogenous lifted equality.+--+-- This class is stronger version of 'Eq1' from @base@+--+-- @+-- class (forall a. Eq a => Eq (f a)) => Eq1 f where+-- liftEq :: (a -> b -> Bool) -> f a -> f b -> Bool+-- @+--+-- as we don't require a @a -> b -> Bool@ function.+--+-- Morally 'Eq1' should be a superclass of 'EqP', but it cannot be,+-- as GHC wouldn't allow 'EqP' to be polykinded.+-- https://gitlab.haskell.org/ghc/ghc/-/issues/22682+--+-- == Laws+--+-- [reflexivity] @'eqp' x x ≡ True@+-- [symmetry] @'eqp' x y ≡ 'eqp' y x@+-- [transitivity] @'eqp' x y ≡ 'eqp' y z ≡ True ⇒ 'eqp' x z ≡ True@+-- [compatibility] @'eqp' x y ≡ x '==' y@+-- [extensionality] @'eqp' x y ≡ True ⇒ f x == f y ≡ True@ for polymorphic @f :: forall x. f x -> a@ and @'Eq' a@.+--+-- /Note:/ P stands for phantom.+--+-- @since 1.0.5+#if __GLASGOW_HASKELL__ >= 810+type EqP :: (k -> Type) -> Constraint+#endif+class (forall a. Eq (f a)) => EqP (f :: k -> Type) where+ eqp :: f a -> f b -> Bool++instance EqP ((:~:) a) where+ eqp _ _ = True++instance EqP ((:~~:) a) where+ eqp _ _ = True+++#if MIN_VERSION_base(4,18,0)+instance (EqP a, EqP b) => EqP (Sum a b) where+ eqp (InL x) (InL y) = eqp x y+ eqp (InR x) (InR y) = eqp x y+ eqp _ _ = False++instance (EqP a, EqP b) => EqP (Product a b) where+ eqp (Pair x y) (Pair x' y') = eqp x x' && eqp y y'+#endif++instance (EqP f, EqP g) => EqP (f :+: g) where+ eqp (L1 x) (L1 y) = eqp x y+ eqp (R1 x) (R1 y) = eqp x y+ eqp _ _ = False++instance (EqP a, EqP b) => EqP (a :*: b) where+ eqp (x :*: y) (x' :*: y') = eqp x x' && eqp y y'++instance EqP TR.TypeRep where+ eqp x y = TR.SomeTypeRep x == TR.SomeTypeRep y++instance EqP Proxy where+ eqp _ _ = True++instance Eq a => EqP (Const a) where+ eqp (Const x) (Const y) = x == y++instance EqP StableName where+ eqp = eqStableName
+ src/Data/OrdP.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE Safe #-}+{-# LANGUAGE TypeOperators #-}+#if __GLASGOW_HASKELL__ >= 810+{-# LANGUAGE StandaloneKindSignatures #-}+#endif+module Data.OrdP (+ OrdP (..),+) where++import Control.Applicative (Const (..))+import Data.Kind (Type)+import Data.Proxy (Proxy (..))+import Data.Semigroup ((<>))+import Data.Type.Equality ((:~:) (..), (:~~:) (..))+import GHC.Generics ((:*:) (..), (:+:) (..))++#if MIN_VERSION_base(4,18,0)+import Data.Functor.Product (Product (..))+import Data.Functor.Sum (Sum (..))+#endif++import qualified Type.Reflection as TR++#if __GLASGOW_HASKELL__ >= 810+import Data.Kind (Constraint)+#endif++import Data.EqP++-- | Heterogenous lifted total order.+--+-- This class is stronger version of 'Ord1' from @base@+--+-- @+-- class (forall a. Ord a => Ord (f a)) => Ord1 f where+-- liftCompare :: (a -> b -> Ordering) -> f a -> f b -> Ordering+-- @+--+-- @since 1.0.5+#if __GLASGOW_HASKELL__ >= 810+type OrdP :: (k -> Type) -> Constraint+#endif+class (EqP f, forall a. Ord (f a)) => OrdP (f :: k -> Type) where+ comparep :: f a -> f b -> Ordering++instance OrdP ((:~:) a) where+ comparep _ _ = EQ++instance OrdP ((:~~:) a) where+ comparep _ _ = EQ++#if MIN_VERSION_base(4,18,0)+instance (OrdP a, OrdP b) => OrdP (Sum a b) where+ comparep (InL x) (InL y) = comparep x y+ comparep (InL _) (InR _) = LT+ comparep (InR x) (InR y) = comparep x y+ comparep (InR _) (InL _) = GT++instance (OrdP a, OrdP b) => OrdP (Product a b) where+ comparep (Pair x y) (Pair x' y') = comparep x x' <> comparep y y'+#endif++instance (OrdP f, OrdP g) => OrdP (f :+: g) where+ comparep (L1 x) (L1 y) = comparep x y+ comparep (L1 _) (R1 _) = LT+ comparep (R1 x) (R1 y) = comparep x y+ comparep (R1 _) (L1 _) = GT++instance (OrdP a, OrdP b) => OrdP (a :*: b) where+ comparep (x :*: y) (x' :*: y') = comparep x x' <> comparep y y'++instance OrdP TR.TypeRep where+ comparep x y = compare (TR.SomeTypeRep x) (TR.SomeTypeRep y)++instance OrdP Proxy where+ comparep _ _ = EQ++instance Ord a => OrdP (Const a) where+ comparep (Const x) (Const y) = compare x y
src/Data/Some/GADT.hs view
@@ -34,10 +34,11 @@ -- $setup -- >>> :set -XKindSignatures -XGADTs -- >>> import Data.GADT.Show+-- >>> import Data.Kind (Type) -- | Existential. This is type is useful to hide GADTs' parameters. ----- >>> data Tag :: * -> * where TagInt :: Tag Int; TagBool :: Tag Bool+-- >>> data Tag :: Type -> Type where TagInt :: Tag Int; TagBool :: Tag Bool -- >>> instance GShow Tag where gshowsPrec _ TagInt = showString "TagInt"; gshowsPrec _ TagBool = showString "TagBool" -- >>> classify s = case s of "TagInt" -> [mkGReadResult TagInt]; "TagBool" -> [mkGReadResult TagBool]; _ -> [] -- >>> instance GRead Tag where greadsPrec _ s = [ (r, rest) | (con, rest) <- lex s, r <- classify con ]
src/Data/Some/Newtype.hs view
@@ -36,10 +36,11 @@ -- $setup -- >>> :set -XKindSignatures -XGADTs -- >>> import Data.GADT.Show+-- >>> import Data.Kind (Type) -- | Existential. This is type is useful to hide GADTs' parameters. ----- >>> data Tag :: * -> * where TagInt :: Tag Int; TagBool :: Tag Bool+-- >>> data Tag :: Type -> Type where TagInt :: Tag Int; TagBool :: Tag Bool -- >>> instance GShow Tag where gshowsPrec _ TagInt = showString "TagInt"; gshowsPrec _ TagBool = showString "TagBool" -- >>> classify s = case s of "TagInt" -> [mkGReadResult TagInt]; "TagBool" -> [mkGReadResult TagBool]; _ -> [] -- >>> instance GRead Tag where greadsPrec _ s = [ (r, rest) | (con, rest) <- lex s, r <- classify con ]