semialign 1.2.0.1 → 1.4
raw patch · 5 files changed
Files
- CHANGELOG.md +23/−0
- semialign.cabal +22/−47
- src/Data/Crosswalk.hs +0/−6
- src/Data/Semialign/Internal.hs +90/−72
- src/Data/Zip.hs +0/−2
CHANGELOG.md view
@@ -1,3 +1,26 @@+# 1.4++- Reorder class hierarchy. `Unzip` is now at the bottom, right above `Functor`.+ There are two ways things may break:+ - You may need to add `Unzip` instance if you haven't one already, for example:+ `instance Unzip ((->) e) where unzip = unzipDefault` was added in this patch.+ - `Unzip f` doesn't imply whole hierarchy, so you may need to change `Unzip f` to `Zip f`+ in the constraints of some of your functions.+- Relax laws of Unalign allowing list-like instances.+ - Add `Unalign []` and `Unalign Vector` instances.++# 1.3.1++- Support GHC-8.6.5...GHC-9.10.1++# 1.3++- Depend on `bifunctor-classes-compat` instead of `bifunctors`+ See changelog note in `bifunctors-5.6`: https://hackage.haskell.org/package/bifunctors-5.6/changelog+ This is breaking change, but affects only GHC-8.0 and older users.+ In that case you should check various combinations of newer/older+ `bifunctors`, `these`, and `semialign` packages.+ # 1.2.0.1 - GHC-9.2 support
semialign.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: semialign-version: 1.2.0.1+version: 1.4 synopsis: Align and Zip type-classes from the common Semialign ancestor. @@ -21,19 +21,17 @@ forming lattice-like structure. tested-with:- GHC ==7.4.2- || ==7.6.3- || ==7.8.4- || ==7.10.3- || ==8.0.2- || ==8.2.2- || ==8.4.4- || ==8.6.5- || ==8.8.4- || ==8.10.4- || ==9.0.1- || ==9.2.1- , GHCJS ==8.4+ GHC ==8.6.5+ || ==8.8.4+ || ==8.10.7+ || ==9.0.2+ || ==9.2.8+ || ==9.4.8+ || ==9.6.6+ || ==9.8.4+ || ==9.10.1+ || ==9.12.4+ || ==9.14.1 source-repository head type: git@@ -47,10 +45,8 @@ library default-language: Haskell2010- ghc-options: -Wall+ ghc-options: -Wall -Wno-trustworthy-safe - if impl(ghc >=8.0)- ghc-options: -Wno-trustworthy-safe if impl(ghc >=9.2) ghc-options: -Wno-noncanonical-monoid-instances @@ -66,41 +62,20 @@ -- ghc boot libs build-depends:- base >=4.5.1.0 && <4.17- , containers >=0.4.2.1 && <0.7- , transformers >=0.3.0.0 && <0.7+ base >=4.12.0.0 && <4.23+ , containers >=0.6.0.1 && <0.9 -- These- build-depends: these >=1.1.1.1 && <1.2+ build-depends: these >=1.2.1 && <1.3 -- other dependencies build-depends:- hashable >=1.2.7.0 && <1.5- , indexed-traversable >=0.1.1 && <0.2- , indexed-traversable-instances >=0.1 && <0.2- , tagged >=0.8.6 && <0.9+ hashable >=1.4.4.0 && <1.6+ , indexed-traversable >=0.1.4 && <0.2+ , indexed-traversable-instances >=0.1.2 && <0.2+ , tagged >=0.8.8 && <0.9 , unordered-containers >=0.2.8.0 && <0.3- , vector >=0.12.0.2 && <0.13-- -- base shims- if !impl(ghc >=8.2)- build-depends: bifunctors >=5.5.4 && <5.6-- if !impl(ghc >=8.0)- build-depends:- semigroups >=0.18.5 && <0.20- , transformers >=0.3.0.0 && <0.7- , transformers-compat >=0.6.5 && <0.8-- -- Ensure Data.Functor.Classes is always available- if impl(ghc >=7.10)- build-depends: transformers >=0.4.2.0-- if !impl(ghc >=7.10)- build-depends: void >=0.7.3 && <0.8-- if impl(ghc <7.5)- build-depends: ghc-prim+ , vector >=0.13.0.0 && <0.14 if flag(semigroupoids)- build-depends: semigroupoids >=5.3.2 && <5.4+ build-depends: semigroupoids >=6.0.1 && <6.1
src/Data/Crosswalk.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE Trustworthy #-} module Data.Crosswalk ( -- * Crosswalk@@ -42,9 +41,7 @@ sequenceL :: (Align f) => t (f a) -> f (t a) sequenceL = crosswalk id -#if __GLASGOW_HASKELL__ >= 707 {-# MINIMAL crosswalk | sequenceL #-}-#endif instance Crosswalk Identity where crosswalk f (Identity a) = fmap Identity (f a)@@ -106,10 +103,7 @@ bisequenceL :: (Align f) => t (f a) (f b) -> f (t a b) bisequenceL = bicrosswalk id id -#if __GLASGOW_HASKELL__ >= 707 {-# MINIMAL bicrosswalk | bisequenceL #-}-#endif- instance Bicrosswalk Either where bicrosswalk f _ (Left x) = Left <$> f x
src/Data/Semialign/Internal.hs view
@@ -2,18 +2,16 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE PolyKinds #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE UndecidableInstances #-}-#if __GLASGOW_HASKELL__ >= 706-{-# LANGUAGE PolyKinds #-}-#endif module Data.Semialign.Internal where import Prelude (Bool (..), Either (..), Eq (..), Functor (fmap), Int, Maybe (..),- Monad (..), Ord (..), Ordering (..), String, error, flip, fst, id,- maybe, snd, uncurry, ($), (++), (.))+ Monad (..), Ord (..), Ordering (..), String, error, flip, fst, id, maybe,+ snd, uncurry, ($), (++), (.)) import qualified Prelude as Prelude @@ -45,38 +43,22 @@ import qualified Data.Vector as V import qualified Data.Vector.Fusion.Stream.Monadic as Stream -#if MIN_VERSION_vector(0,11,0) import Data.Vector.Fusion.Bundle.Monadic (Bundle (..)) import qualified Data.Vector.Fusion.Bundle.Monadic as Bundle import qualified Data.Vector.Fusion.Bundle.Size as Bundle-#else-import qualified Data.Vector.Fusion.Stream.Size as Stream-#endif -#if MIN_VERSION_containers(0,5,0) import Data.Map.Lazy (Map) import qualified Data.Map.Lazy as Map import Data.IntMap.Lazy (IntMap) import qualified Data.IntMap.Lazy as IntMap -#if MIN_VERSION_containers(0,5,9) import qualified Data.IntMap.Merge.Lazy as IntMap import qualified Data.Map.Merge.Lazy as Map-#endif --- containers <0.5-#else-import Data.Map (Map)-import qualified Data.Map as Map--import Data.IntMap (IntMap)-import qualified Data.IntMap as IntMap-#endif- #if !(MIN_VERSION_base(4,16,0)) import Data.Semigroup (Option (..))-#endif +#endif import Data.These import Data.These.Combinators@@ -95,7 +77,7 @@ -- The laws of 'align' and 'zip' resemble lattice laws. -- There is a plenty of laws, but they are simply satisfied. ----- And an addition property if @f@ is 'Foldable',+-- And an additional property if @f@ is 'Foldable', -- which tries to enforce 'align'-feel: -- neither values are duplicated nor lost. --@@ -139,17 +121,7 @@ -- ≡ mapMaybe justHere (toList (align x y)) -- @ -------- And an addition property if @f@ is 'Foldable',--- which tries to enforce 'align'-feel:--- neither values are duplicated nor lost.------ @--- toList x = toListOf (folded . here) (align x y)--- = mapMaybe justHere (toList (align x y))--- @----class Functor f => Semialign f where+class Unzip f => Semialign f where -- | Analogous to @'zip'@, combines two structures by taking the union of -- their shapes and using @'These'@ to hold the elements. align :: f a -> f b -> f (These a b)@@ -160,9 +132,7 @@ alignWith :: (These a b -> c) -> f a -> f b -> f c alignWith f a b = f <$> align a b -#if __GLASGOW_HASKELL__ >= 707 {-# MINIMAL (align | alignWith) #-}-#endif -- | A unit of 'align'. --@@ -186,10 +156,18 @@ -- == Laws -- -- @--- uncurry align (unalign xs) ≡ xs -- unalign (align xs ys) ≡ (xs, ys) -- @ --+-- Previously 'Unalign' included a right inverse law+--+-- @+-- uncurry align (unalign xs) ≡ xs+-- @+--+-- But this law was removed in 1.4 to allow list-like instances,+-- where unalign necessarily loses some information.+-- -- == Compatibility note -- -- In version 1 'unalign' was changed to return @(f a, f b)@ pair,@@ -206,11 +184,8 @@ unalignWith :: (c -> These a b) -> f c -> (f a, f b) unalignWith f fx = unalign (fmap f fx) -#if __GLASGOW_HASKELL__ >= 707 {-# MINIMAL unalignWith | unalign #-}-#endif - -- | Functors supporting a 'zip' operation that takes the intersection of -- non-uniform shapes. --@@ -294,9 +269,7 @@ zipWith :: (a -> b -> c) -> f a -> f b -> f c zipWith f a b = uncurry f <$> zip a b -#if __GLASGOW_HASKELL__ >= 707 {-# MINIMAL (zip | zipWith) #-}-#endif -- | Zippable functors supporting left and right units --@@ -330,16 +303,14 @@ -- -- For sequence-like types this holds, but for Map-like it doesn't. ---class Zip f => Unzip f where+class Functor f => Unzip f where unzipWith :: (c -> (a, b)) -> f c -> (f a, f b) unzipWith f = unzip . fmap f unzip :: f (a, b) -> (f a, f b) unzip = unzipWith id -#if __GLASGOW_HASKELL__ >= 707 {-# MINIMAL unzipWith | unzip #-}-#endif unzipDefault :: Functor f => f (a, b) -> (f a, f b) unzipDefault x = (fst <$> x, snd <$> x)@@ -374,6 +345,12 @@ -- base ------------------------------------------------------------------------------- +-- |+--+-- @since 1.4+instance Unzip ((->) e) where+ unzip = unzipDefault+ instance Semialign ((->) e) where align f g x = These (f x) (g x) alignWith h f g x = h (These (f x) (g x))@@ -439,6 +416,16 @@ instance Unzip [] where unzip = Prelude.unzip +-- |+--+-- @since 1.4+instance Unalign [] where+ unalign = Prelude.foldr f ([], []) where+ f :: These a b -> ([a], [b]) -> ([a], [b])+ f (This x) ~(xs, ys) = (x : xs, ys)+ f (That y) ~(xs, ys) = ( xs, y : ys)+ f (These x y) ~(xs, ys) = (x : xs, y : ys)+ instance SemialignWithIndex Int [] instance ZipWithIndex Int [] instance RepeatWithIndex Int []@@ -460,6 +447,10 @@ unzip (ZipList xs) = (ZipList ys, ZipList zs) where (ys, zs) = unzip xs +instance Unalign ZipList where+ unalign (ZipList xs) = (ZipList ys, ZipList zs) where+ (ys, zs) = unalign xs+ instance SemialignWithIndex Int ZipList instance ZipWithIndex Int ZipList instance RepeatWithIndex Int ZipList@@ -529,12 +520,8 @@ nil = Seq.empty instance Unzip Seq where-#if MIN_VERSION_containers(0,5,11) unzip = Seq.unzip unzipWith = Seq.unzipWith-#else- unzip = unzipDefault-#endif instance Zip Seq where zip = Seq.zip@@ -563,17 +550,9 @@ ------------------------------------------------------------------------------- instance Ord k => Semialign (Map k) where-#if MIN_VERSION_containers(0,5,9) alignWith f = Map.merge (Map.mapMissing (\_ x -> f (This x))) (Map.mapMissing (\_ y -> f (That y))) (Map.zipWithMatched (\_ x y -> f (These x y)))-#elif MIN_VERSION_containers(0,5,0)- alignWith f = Map.mergeWithKey (\_ x y -> Just $ f $ These x y) (fmap (f . This)) (fmap (f . That))-#else- align m n = Map.unionWith merge (Map.map This m) (Map.map That n)- where merge (This a) (That b) = These a b- merge _ _ = oops "Align Map: merge"-#endif instance (Ord k) => Align (Map k) where nil = Map.empty@@ -587,17 +566,9 @@ zipWith = Map.intersectionWith instance Semialign IntMap where-#if MIN_VERSION_containers(0,5,9) alignWith f = IntMap.merge (IntMap.mapMissing (\_ x -> f (This x))) (IntMap.mapMissing (\_ y -> f (That y))) (IntMap.zipWithMatched (\_ x y -> f (These x y)))-#elif MIN_VERSION_containers(0,5,0)- alignWith f = IntMap.mergeWithKey (\_ x y -> Just $ f $ These x y) (fmap (f . This)) (fmap (f . That))-#else- align m n = IntMap.unionWith merge (IntMap.map This m) (IntMap.map That n)- where merge (This a) (That b) = These a b- merge _ _ = oops "Align IntMap: merge"-#endif instance Align IntMap where nil = IntMap.empty@@ -718,17 +689,19 @@ ------------------------------------------------------------------------------- -- Based on the Data.Vector.Fusion.Stream.Monadic zipWith implementation++-- |+--+-- @since 1.4+instance Monad m => Unzip (Stream m) where+ unzip = unzipDefault+ instance Monad m => Align (Stream m) where nil = Stream.empty instance Monad m => Semialign (Stream m) where-#if MIN_VERSION_vector(0,11,0) alignWith f (Stream stepa ta) (Stream stepb tb) = Stream step (ta, tb, Nothing, False)-#else- alignWith f (Stream stepa ta na) (Stream stepb tb nb)- = Stream step (ta, tb, Nothing, False) (Stream.larger na nb)-#endif where step (sa, sb, Nothing, False) = do r <- stepa sa@@ -750,21 +723,58 @@ _ -> Skip (sa, sb, Nothing, False) #endif +-- |+--+-- @since 1.4+instance Monad m => Unalign (Stream m) where+ unalign (Stream stepa s) = (Stream stepb s, Stream stepc s)+ where+ stepb i = do+ r <- stepa i+ return $ case r of+ Done -> Done+ Skip j -> Skip j+ Yield (This x) j -> Yield x j+ Yield (These x _) j -> Yield x j+ Yield (That _) j -> Skip j++ stepc i = do+ r <- stepa i+ return $ case r of+ Done -> Done+ Skip j -> Skip j+ Yield (This _) j -> Skip j+ Yield (These _ y) j -> Yield y j+ Yield (That y) j -> Yield y j+ instance Monad m => Zip (Stream m) where zipWith = Stream.zipWith -#if MIN_VERSION_vector(0,11,0)+-- |+--+-- @since 1.4+instance Monad m => Unzip (Bundle m v) where+ unzip = unzipDefault+ instance Monad m => Align (Bundle m v) where nil = Bundle.empty instance Monad m => Semialign (Bundle m v) where alignWith f Bundle{sElems = sa, sSize = na} Bundle{sElems = sb, sSize = nb} = Bundle.fromStream (alignWith f sa sb) (Bundle.larger na nb)-#endif instance Monad m => Zip (Bundle m v) where zipWith = Bundle.zipWith +-- |+--+-- @since 1.4+instance Monad m => Unalign (Bundle m v) where+ unalign Bundle { sElems = xys, sSize = n } =+ (Bundle.fromStream xs (Bundle.toMax n), Bundle.fromStream ys (Bundle.toMax n))+ where+ ~(xs, ys) = unalign xys+ instance Semialign V.Vector where alignWith = alignVectorWith @@ -776,6 +786,14 @@ instance Unzip V.Vector where unzip = V.unzip++-- |+--+-- @since 1.4+instance Unalign V.Vector where+ -- TODO: it would be more efficient to do unalign imperatively.+ unalign xys = (unstream xs, unstream ys) where+ ~(xs, ys) = unalign (stream xys) alignVectorWith :: (Vector v a, Vector v b, Vector v c) => (These a b -> c) -> v a -> v b -> v c
src/Data/Zip.hs view
@@ -50,6 +50,4 @@ Zippy f <*> Zippy x = Zippy $ zipWith ($) f x #endif -#if MIN_VERSION_base(4,10,0) liftA2 f (Zippy x) (Zippy y) = Zippy $ zipWith f x y-#endif