packages feed

alignment 0.1.0.6 → 0.2.0.0

raw patch · 6 files changed

+1934/−714 lines, 6 filesdep +alignmentdep +containersdep +criteriondep ~basedep ~lensdep ~semigroupoidsPVP ok

version bump matches the API change (PVP)

Dependencies added: alignment, containers, criterion, deepseq, process, vector

Dependency ranges changed: base, lens, semigroupoids

API changes (from Hackage documentation)

- Data.Alignment: allThese :: forall (f :: Type -> Type) a b. Traversable f => Traversal' (This f a b) (a, b)
- Data.Alignment: allThese1 :: forall (f :: Type -> Type) a b. Traversable f => Traversal' (This f a b) a
- Data.Alignment: allThese2 :: forall (f :: Type -> Type) a b. Traversable f => Traversal' (This f a b) b
- Data.Alignment: allTheseThoseA :: forall (f :: Type -> Type) a b a'. Traversable f => Traversal (This f a b) (This f a' b) a a'
- Data.Alignment: allTheseThoseA1 :: forall (f :: Type -> Type) a b a'. Traversable1 f => Traversal1 (This f a b) (This f a' b) a a'
- Data.Alignment: allTheseThoseB :: forall (f :: Type -> Type) a b b'. Traversable f => Traversal (This f a b) (This f a b') b b'
- Data.Alignment: allTheseThoseB1 :: forall (f :: Type -> Type) a b b'. Traversable1 f => Traversal1 (This f a b) (This f a b') b b'
- Data.Alignment: allThose :: forall (f1 :: Type -> Type) a b f2. Applicative f2 => (Either (NonEmpty a) (NonEmpty b) -> f2 (Either (NonEmpty a) (NonEmpty b))) -> This f1 a b -> f2 (This f1 a b)
- Data.Alignment: allThoseA :: forall (f1 :: Type -> Type) a b f2. Applicative f2 => (NonEmpty a -> f2 (NonEmpty a)) -> This f1 a b -> f2 (This f1 a b)
- Data.Alignment: allThoseAOr :: forall (f1 :: Type -> Type) a b f2. Applicative f2 => ([a] -> f2 [a]) -> This f1 a b -> f2 (This f1 a b)
- Data.Alignment: allThoseB :: forall (f1 :: Type -> Type) a b f2. Applicative f2 => (NonEmpty b -> f2 (NonEmpty b)) -> This f1 a b -> f2 (This f1 a b)
- Data.Alignment: allThoseBOr :: forall (f1 :: Type -> Type) a b f2. Applicative f2 => ([b] -> f2 [b]) -> This f1 a b -> f2 (This f1 a b)
- Data.Alignment: instance (Data.Functor.Classes.Eq1 f, GHC.Classes.Eq a) => Data.Functor.Classes.Eq1 (Data.Alignment.This f a)
- Data.Alignment: instance (Data.Functor.Classes.Eq1 f, GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (Data.Alignment.This f a b)
- Data.Alignment: instance (Data.Functor.Classes.Ord1 f, GHC.Classes.Ord a) => Data.Functor.Classes.Ord1 (Data.Alignment.This f a)
- Data.Alignment: instance (Data.Functor.Classes.Ord1 f, GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (Data.Alignment.This f a b)
- Data.Alignment: instance (Data.Functor.Classes.Show1 f, GHC.Show.Show a) => Data.Functor.Classes.Show1 (Data.Alignment.This f a)
- Data.Alignment: instance (Data.Functor.Classes.Show1 f, GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Data.Alignment.This f a b)
- Data.Alignment: instance (GHC.Base.Monoid a, GHC.Base.Applicative f) => GHC.Base.Applicative (Data.Alignment.This f a)
- Data.Alignment: instance (GHC.Base.Semigroup a, Data.Functor.Bind.Class.Apply f) => Data.Functor.Bind.Class.Apply (Data.Alignment.This f a)
- Data.Alignment: instance Data.Alignment.Align Control.Applicative.ZipList
- Data.Alignment: instance Data.Alignment.Align GHC.Maybe.Maybe
- Data.Alignment: instance Data.Alignment.Align []
- Data.Alignment: instance Data.Alignment.Semialign Control.Applicative.ZipList
- Data.Alignment: instance Data.Alignment.Semialign Data.Functor.Identity.Identity
- Data.Alignment: instance Data.Alignment.Semialign GHC.Base.NonEmpty
- Data.Alignment: instance Data.Alignment.Semialign GHC.Maybe.Maybe
- Data.Alignment: instance Data.Alignment.Semialign []
- Data.Alignment: instance Data.Foldable.Foldable f => Data.Bifoldable.Bifoldable (Data.Alignment.This f)
- Data.Alignment: instance Data.Foldable1.Foldable1 f => Data.Bifoldable1.Bifoldable1 (Data.Alignment.This f)
- Data.Alignment: instance Data.Semigroup.Traversable.Class.Traversable1 f => Data.Semigroup.Traversable.Class.Bitraversable1 (Data.Alignment.This f)
- Data.Alignment: instance Data.Traversable.Traversable f => Data.Bitraversable.Bitraversable (Data.Alignment.This f)
- Data.Alignment: instance GHC.Base.Functor f => Data.Bifunctor.Bifunctor (Data.Alignment.This f)
- Data.Alignment: instance GHC.Base.Functor f => Data.Bifunctor.Swap.Swap (Data.Alignment.This f)
- Data.Alignment: instance GHC.Base.Functor f => GHC.Base.Functor (Data.Alignment.This f a)
- Data.Alignment: instance GHC.Base.Monoid (Data.Alignment.This [] a b)
- Data.Alignment: instance GHC.Base.Semigroup (Data.Alignment.This GHC.Base.NonEmpty a b)
- Data.Alignment: instance GHC.Base.Semigroup (Data.Alignment.This [] a b)
+ Data.Alignment: _This :: AsThis s f g a b => Prism' s (This f g a b)
+ Data.Alignment: alignEmpty :: forall f (g :: Type -> Type) a. (Align f g, Eq1 f, Eq1 g, Eq a) => f a -> f a -> Bool
+ Data.Alignment: alignLeftIdentity :: forall f (g :: Type -> Type) a b. (Align f g, Eq1 f, Eq a, Eq b) => f a -> f b -> Bool
+ Data.Alignment: alignRightIdentity :: forall f (g :: Type -> Type) a b. (Align f g, Eq1 f, Eq a, Eq b) => f a -> f b -> Bool
+ Data.Alignment: aligned :: Unalign f g => Iso' (f a, f b) (This f g a b)
+ Data.Alignment: class ReviewThis s f g a b => AsThis s (f :: Type -> Type) (g :: Type -> Type) a b | s -> f g a b
+ Data.Alignment: class GetThis s (f :: Type -> Type) (g :: Type -> Type) a b | s -> f g a b
+ Data.Alignment: class GetThis s f g a b => HasThis s (f :: Type -> Type) (g :: Type -> Type) a b | s -> f g a b
+ Data.Alignment: class ReviewThis s (f :: Type -> Type) (g :: Type -> Type) a b | s -> f g a b
+ Data.Alignment: class Semialign f g => Unalign (f :: Type -> Type) (g :: Type -> Type)
+ Data.Alignment: foldA :: forall (f :: Type -> Type) (g :: Type -> Type) a b. (Foldable f, Foldable g) => Fold (This f g a b) a
+ Data.Alignment: foldA1 :: forall (f :: Type -> Type) (g :: Type -> Type) a b. (Foldable1 f, Foldable1 g) => Fold1 (This f g a b) a
+ Data.Alignment: foldB :: forall (f :: Type -> Type) (g :: Type -> Type) a b. (Foldable f, Foldable g) => Fold (This f g a b) b
+ Data.Alignment: foldB1 :: forall (f :: Type -> Type) (g :: Type -> Type) a b. (Foldable1 f, Foldable1 g) => Fold1 (This f g a b) b
+ Data.Alignment: getThis :: GetThis s f g a b => Getter s (This f g a b)
+ Data.Alignment: instance (Control.DeepSeq.NFData (f (a, b)), Control.DeepSeq.NFData (g a), Control.DeepSeq.NFData (g b)) => Control.DeepSeq.NFData (Data.Alignment.This f g a b)
+ Data.Alignment: instance (Data.Foldable.Foldable f, Data.Foldable.Foldable g) => Data.Bifoldable.Bifoldable (Data.Alignment.This f g)
+ Data.Alignment: instance (Data.Foldable.Foldable f, Data.Foldable.Foldable g) => Data.Foldable.Foldable (Data.Alignment.This f g a)
+ Data.Alignment: instance (Data.Foldable1.Foldable1 f, Data.Foldable1.Foldable1 g) => Data.Bifoldable1.Bifoldable1 (Data.Alignment.This f g)
+ Data.Alignment: instance (Data.Foldable1.Foldable1 f, Data.Foldable1.Foldable1 g) => Data.Foldable1.Foldable1 (Data.Alignment.This f g a)
+ Data.Alignment: instance (Data.Functor.Classes.Eq1 f, Data.Functor.Classes.Eq1 g) => Data.Functor.Classes.Eq2 (Data.Alignment.This f g)
+ Data.Alignment: instance (Data.Functor.Classes.Eq1 f, Data.Functor.Classes.Eq1 g, GHC.Classes.Eq a) => Data.Functor.Classes.Eq1 (Data.Alignment.This f g a)
+ Data.Alignment: instance (Data.Functor.Classes.Eq1 f, Data.Functor.Classes.Eq1 g, GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (Data.Alignment.This f g a b)
+ Data.Alignment: instance (Data.Functor.Classes.Ord1 f, Data.Functor.Classes.Ord1 g) => Data.Functor.Classes.Ord2 (Data.Alignment.This f g)
+ Data.Alignment: instance (Data.Functor.Classes.Ord1 f, Data.Functor.Classes.Ord1 g, GHC.Classes.Ord a) => Data.Functor.Classes.Ord1 (Data.Alignment.This f g a)
+ Data.Alignment: instance (Data.Functor.Classes.Ord1 f, Data.Functor.Classes.Ord1 g, GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (Data.Alignment.This f g a b)
+ Data.Alignment: instance (Data.Functor.Classes.Show1 f, Data.Functor.Classes.Show1 g) => Data.Functor.Classes.Show2 (Data.Alignment.This f g)
+ Data.Alignment: instance (Data.Functor.Classes.Show1 f, Data.Functor.Classes.Show1 g, GHC.Show.Show a) => Data.Functor.Classes.Show1 (Data.Alignment.This f g a)
+ Data.Alignment: instance (Data.Functor.Classes.Show1 f, Data.Functor.Classes.Show1 g, GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Data.Alignment.This f g a b)
+ Data.Alignment: instance (Data.Semigroup.Traversable.Class.Traversable1 f, Data.Semigroup.Traversable.Class.Traversable1 g) => Data.Semigroup.Traversable.Class.Bitraversable1 (Data.Alignment.This f g)
+ Data.Alignment: instance (Data.Semigroup.Traversable.Class.Traversable1 f, Data.Semigroup.Traversable.Class.Traversable1 g) => Data.Semigroup.Traversable.Class.Traversable1 (Data.Alignment.This f g a)
+ Data.Alignment: instance (Data.Traversable.Traversable f, Data.Traversable.Traversable g) => Data.Bitraversable.Bitraversable (Data.Alignment.This f g)
+ Data.Alignment: instance (Data.Traversable.Traversable f, Data.Traversable.Traversable g) => Data.Traversable.Traversable (Data.Alignment.This f g a)
+ Data.Alignment: instance (GHC.Base.Functor f, GHC.Base.Functor g) => Data.Bifunctor.Bifunctor (Data.Alignment.This f g)
+ Data.Alignment: instance (GHC.Base.Functor f, GHC.Base.Functor g) => GHC.Base.Functor (Data.Alignment.This f g a)
+ Data.Alignment: instance (GHC.Base.Monoid (f (a, b)), GHC.Base.Semigroup (g a), GHC.Base.Semigroup (g b)) => GHC.Base.Monoid (Data.Alignment.This f g a b)
+ Data.Alignment: instance (GHC.Base.Semigroup (f (a, b)), GHC.Base.Semigroup (g a), GHC.Base.Semigroup (g b)) => GHC.Base.Semigroup (Data.Alignment.This f g a b)
+ Data.Alignment: instance Data.Alignment.Align Control.Applicative.ZipList GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Align Data.IntMap.Internal.IntMap Data.IntMap.Internal.IntMap
+ Data.Alignment: instance Data.Alignment.Align Data.Sequence.Internal.Seq GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Align Data.Vector.Vector GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Align GHC.Maybe.Maybe Data.Functor.Identity.Identity
+ Data.Alignment: instance Data.Alignment.Align [] GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.AsThis (Data.Alignment.This f g a b) f g a b
+ Data.Alignment: instance Data.Alignment.GetThis (Data.Alignment.This f g a b) f g a b
+ Data.Alignment: instance Data.Alignment.HasThis (Data.Alignment.This f g a b) f g a b
+ Data.Alignment: instance Data.Alignment.ReviewThis (Data.Alignment.This f g a b) f g a b
+ Data.Alignment: instance Data.Alignment.Semialign ((->) r) Data.Functor.Identity.Identity
+ Data.Alignment: instance Data.Alignment.Semialign (Data.Functor.Const.Const m) Data.Functor.Identity.Identity
+ Data.Alignment: instance Data.Alignment.Semialign Control.Applicative.ZipList GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Semialign Data.Functor.Identity.Identity Data.Functor.Identity.Identity
+ Data.Alignment: instance Data.Alignment.Semialign Data.IntMap.Internal.IntMap Data.IntMap.Internal.IntMap
+ Data.Alignment: instance Data.Alignment.Semialign Data.Sequence.Internal.Seq GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Semialign Data.Vector.Vector GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Semialign GHC.Base.NonEmpty GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Semialign GHC.Maybe.Maybe Data.Functor.Identity.Identity
+ Data.Alignment: instance Data.Alignment.Semialign [] GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Unalign Control.Applicative.ZipList GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Unalign Data.Functor.Identity.Identity Data.Functor.Identity.Identity
+ Data.Alignment: instance Data.Alignment.Unalign Data.Sequence.Internal.Seq GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Unalign Data.Vector.Vector GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Unalign GHC.Base.NonEmpty GHC.Base.NonEmpty
+ Data.Alignment: instance Data.Alignment.Unalign GHC.Maybe.Maybe Data.Functor.Identity.Identity
+ Data.Alignment: instance Data.Alignment.Unalign [] GHC.Base.NonEmpty
+ Data.Alignment: instance GHC.Base.Functor f => Data.Bifunctor.Swap.Swap (Data.Alignment.This f g)
+ Data.Alignment: instance GHC.Base.Functor f => GHC.Generics.Generic1 (Data.Alignment.This f g a)
+ Data.Alignment: instance GHC.Base.Monoid e => Data.Alignment.Semialign ((,) e) Data.Functor.Identity.Identity
+ Data.Alignment: instance GHC.Base.Monoid m => Data.Alignment.Align (Data.Functor.Const.Const m) Data.Functor.Identity.Identity
+ Data.Alignment: instance GHC.Classes.Ord k => Data.Alignment.Align (Data.Map.Internal.Map k) (Data.Map.Internal.Map k)
+ Data.Alignment: instance GHC.Classes.Ord k => Data.Alignment.Semialign (Data.Map.Internal.Map k) (Data.Map.Internal.Map k)
+ Data.Alignment: instance GHC.Generics.Generic (Data.Alignment.This f g a b)
+ Data.Alignment: matchThis :: AsThis s f g a b => s -> Maybe (This f g a b)
+ Data.Alignment: reviewThis :: ReviewThis s f g a b => Review s (This f g a b)
+ Data.Alignment: semialignCoherence :: forall f (g :: Type -> Type) a b. (Semialign f g, Eq1 f, Eq1 g, Eq a, Eq b) => f a -> f b -> Bool
+ Data.Alignment: semialignNaturality :: forall f (g :: Type -> Type) c d a b. (Semialign f g, Eq1 f, Eq1 g, Eq c, Eq d) => (a -> c) -> (b -> d) -> f a -> f b -> Bool
+ Data.Alignment: semialignSymmetry :: forall f (g :: Type -> Type) a b. (Semialign f g, Eq1 f, Eq1 g, Eq a, Eq b) => f a -> f b -> Bool
+ Data.Alignment: semialignWithLaw :: forall f (g :: Type -> Type) c d a b. (Semialign f g, Eq1 f, Eq1 g, Eq c, Eq d) => ((a, b) -> (c, d)) -> (a -> c) -> (b -> d) -> f a -> f b -> Bool
+ Data.Alignment: setThis :: HasThis s f g a b => This f g a b -> s -> s
+ Data.Alignment: this' :: HasThis s f g a b => Lens' s (This f g a b)
+ Data.Alignment: thoseLeft :: forall (f1 :: Type -> Type) g a b f2. Applicative f2 => (g a -> f2 (g a)) -> This f1 g a b -> f2 (This f1 g a b)
+ Data.Alignment: thoseRight :: forall (f1 :: Type -> Type) g a b f2. Applicative f2 => (g b -> f2 (g b)) -> This f1 g a b -> f2 (This f1 g a b)
+ Data.Alignment: traverseA :: forall (f :: Type -> Type) (g :: Type -> Type) a b a'. (Traversable f, Traversable g) => Traversal (This f g a b) (This f g a' b) a a'
+ Data.Alignment: traverseA1 :: forall (f :: Type -> Type) (g :: Type -> Type) a b a'. (Traversable1 f, Traversable1 g) => Traversal1 (This f g a b) (This f g a' b) a a'
+ Data.Alignment: traverseB :: forall (f :: Type -> Type) (g :: Type -> Type) a b b'. (Traversable f, Traversable g) => Traversal (This f g a b) (This f g a b') b b'
+ Data.Alignment: traverseB1 :: forall (f :: Type -> Type) (g :: Type -> Type) a b b'. (Traversable1 f, Traversable1 g) => Traversal1 (This f g a b) (This f g a b') b b'
+ Data.Alignment: type This' (f :: Type -> Type) a b = This f f a b
+ Data.Alignment: unalign :: Unalign f g => This f g a b -> (f a, f b)
+ Data.Alignment: unalignNaturality :: forall (f :: Type -> Type) (g :: Type -> Type) c d a b. (Unalign f g, Eq1 f, Eq c, Eq d) => (a -> c) -> (b -> d) -> This f g a b -> Bool
+ Data.Alignment: unalignRoundtrip :: forall f (g :: Type -> Type) a b. (Unalign f g, Eq1 f, Eq a, Eq b) => f a -> f b -> Bool
+ Data.Alignment: unalignWith :: Unalign f g => (a -> c) -> (b -> d) -> This f g a b -> (f c, f d)
+ Data.Alignment: unaligned :: forall (f :: Type -> Type) (g :: Type -> Type) a b. Unalign f g => Iso' (This f g a b) (f a, f b)
- Data.Alignment: This :: f (a, b) -> Maybe (Either (NonEmpty a) (NonEmpty b)) -> This (f :: Type -> Type) a b
+ Data.Alignment: This :: f (a, b) -> Maybe (Either (g a) (g b)) -> This (f :: Type -> Type) (g :: Type -> Type) a b
- Data.Alignment: align :: Semialign f => f a -> f b -> This f a b
+ Data.Alignment: align :: Semialign f g => f a -> f b -> This f g a b
- Data.Alignment: alignWith :: Semialign f => ((a, b) -> (c, d)) -> (a -> c) -> (b -> d) -> f a -> f b -> This f c d
+ Data.Alignment: alignWith :: Semialign f g => ((a, b) -> (c, d)) -> (a -> c) -> (b -> d) -> f a -> f b -> This f g c d
- Data.Alignment: alignWith' :: Semialign f => (a -> c) -> (b -> d) -> f a -> f b -> This f c d
+ Data.Alignment: alignWith' :: Semialign f g => (a -> c) -> (b -> d) -> f a -> f b -> This f g c d
- Data.Alignment: class Semialign f => Align (f :: Type -> Type)
+ Data.Alignment: class Semialign f g => Align (f :: Type -> Type) (g :: Type -> Type)
- Data.Alignment: class Functor f => Semialign (f :: Type -> Type)
+ Data.Alignment: class (Functor f, Functor g) => Semialign (f :: Type -> Type) (g :: Type -> Type) | f -> g
- Data.Alignment: data This (f :: Type -> Type) a b
+ Data.Alignment: data This (f :: Type -> Type) (g :: Type -> Type) a b
- Data.Alignment: nil :: Align f => f a
+ Data.Alignment: nil :: Align f g => f a
- Data.Alignment: these :: forall f1 a b f' f2. Functor f2 => (f1 (a, b) -> f2 (f' (a, b))) -> This f1 a b -> f2 (This f' a b)
+ Data.Alignment: these :: forall f1 (g :: Type -> Type) a b f' f2. Functor f2 => (f1 (a, b) -> f2 (f' (a, b))) -> This f1 g a b -> f2 (This f' g a b)
- Data.Alignment: those :: forall (f1 :: Type -> Type) a b f2. Functor f2 => (Maybe (Either (NonEmpty a) (NonEmpty b)) -> f2 (Maybe (Either (NonEmpty a) (NonEmpty b)))) -> This f1 a b -> f2 (This f1 a b)
+ Data.Alignment: those :: forall (f1 :: Type -> Type) g a b g' f2. Functor f2 => (Maybe (Either (g a) (g b)) -> f2 (Maybe (Either (g' a) (g' b)))) -> This f1 g a b -> f2 (This f1 g' a b)

Files

LICENCE view
@@ -1,4 +1,4 @@-Copyright (c) 2022-2025 Tony Morris+Copyright (c) 2022-2026 Tony Morris  All rights reserved. 
alignment.cabal view
@@ -1,38 +1,112 @@--- documentation, see http://haskell.org/cabal/users-guide/--name:                   alignment-version:                0.1.0.6-synopsis:               Zip-alignment+cabal-version:        2.4+name:                 alignment+version:              0.2.0.0+synopsis:             Principled functor alignment with leftovers description:-  Zipping with alignment-  .-  <<https://logo.systemf.com.au/systemf-450x450.png>>-license:                BSD3-license-file:           LICENCE-author:                 Tony Morris <oᴉ˙ldɟb@llǝʞsɐɥ>-maintainer:             Tony Morris <oᴉ˙ldɟb@llǝʞsɐɥ>-copyright:              Copyright (C) 2022-2025 Tony Morris-category:               Data-build-type:             Simple-extra-source-files:     changelog.md-cabal-version:          >=1.10-homepage:               https://gitlab.com/system-f/code/alignment-bug-reports:            https://gitlab.com/system-f/code/alignment/issues-tested-with:            GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.3, GHC == 8.6.1, GHC == 9.4.8+                      A principled approach to zipping functors that preserves both matched+                      pairs and leftovers.+                      .+                      The @alignment@ library provides type classes and operations for aligning+                      two functors into a structure (@This@) that captures:+                      .+                      * Matched pairs where both functors have elements at the same position+                      .+                      * Leftovers when one functor is longer than the other+                      .+                      This is more principled than traditional @zip@ which silently discards+                      extra elements. The library uses functional dependencies (@f -> g@) to+                      relate the \"paired\" functor to the \"leftover\" functor, ensuring type safety.+                      .+                      Key features:+                      .+                      * @Semialign@, @Align@, and @Unalign@ type classes with comprehensive laws+                      .+                      * @Unalign@ provides inverse operation to recover original functors+                      .+                      * Full lens\/optics integration+                      .+                      * Instances for common functors: @[]@, @Maybe@, @NonEmpty@, @Vector@,+                        @Map@, @Seq@, and more+                      .+                      * Testable law-checking functions for property-based testing+                      .+                      * Complete documentation with 211 doctests+                      .+                      Example:+                      .+                      > import Data.Alignment+                      >+                      > -- Align two lists of different lengths+                      > align [1,2,3] [10,20] :: This [] NonEmpty Int Int+                      > -- Result: This [(1,10),(2,20)] (Just (Left (3 :| [])))+                      .+                      <<https://logo.systemf.com.au/systemf-450x450.png>>+license:              BSD-3-Clause+license-file:         LICENCE+author:               Tony Morris <oᴉ˙ldɟb@llǝʞsɐɥ>+maintainer:           Tony Morris <oᴉ˙ldɟb@llǝʞsɐɥ>+copyright:            Copyright (C) 2022-2026 Tony Morris+category:             Data+build-type:           Simple+extra-doc-files:      changelog.md+homepage:             https://gitlab.com/system-f/code/alignment+bug-reports:          https://gitlab.com/system-f/code/alignment/issues+tested-with:          GHC == 9.6.7 -source-repository       head-  type:                 git-  location:             git@gitlab.com:system-f/code/alignment.git+source-repository     head+  type:               git+  location:           git@gitlab.com:system-f/code/alignment.git  library-  exposed-modules:      Data.Alignment+  exposed-modules:    Data.Alignment -  build-depends:        base >= 4.8 && < 6-                      , bifunctors >= 5 && < 6-                      , lens >= 4.15 && < 6-                      , semigroupoids >= 5.1 && < 7-                      , assoc >= 1 && < 2+  build-depends:      base >= 4.18 && < 6+                    , bifunctors >= 5 && < 6+                    , deepseq >= 1.4 && < 1.6+                    , lens >= 4 && < 6+                    , semigroupoids >= 6 && < 7+                    , assoc >= 1 && < 2+                    , containers >= 0.6 && < 0.8+                    , vector >= 0.12 && < 0.14 -  hs-source-dirs:       src-  default-language:     Haskell2010-  ghc-options:          -Wall+  hs-source-dirs:     src++  default-language:   Haskell2010++  ghc-options:        -Wall++  if flag(dev)+    ghc-options:      -Werror++flag dev+  description:        Enable -Werror for development+  manual:             True+  default:            False++test-suite doctest+  type:               exitcode-stdio-1.0+  hs-source-dirs:     test+  main-is:            Main.hs+  build-depends:      base >= 4.8 && < 6+                    , process >= 1 && < 2+  build-tool-depends: doctest:doctest >= 0.22+  default-language:   Haskell2010+  ghc-options:        -Wall+                      -Wno-inline-rule-shadowing++benchmark alignment-bench+  type:               exitcode-stdio-1.0+  hs-source-dirs:     bench+  main-is:            Main.hs+  build-depends:      base >= 4.8 && < 6+                    , alignment+                    , criterion >= 1.5 && < 1.7+                    , deepseq >= 1.4 && < 1.6+                    , vector >= 0.12 && < 0.14+                    , containers >= 0.6 && < 0.8+  default-language:   Haskell2010+  ghc-options:        -Wall+                      -O2+                      -threaded+                      -rtsopts+                      -with-rtsopts=-N
+ bench/Main.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE ScopedTypeVariables #-}+{- HLINT ignore "Avoid NonEmpty.unzip" -}++module Main where++import Criterion.Main+import Data.Alignment+import qualified Data.Vector as V+import Data.List.NonEmpty (NonEmpty(..))+import Control.DeepSeq (NFData, force)+import Data.Bifunctor (bimap)++-- Force evaluation to prevent benchmark cheating+forceThis :: (NFData (f (a, b)), NFData (g a), NFData (g b)) => This f g a b -> This f g a b+forceThis (This pairs leftover) = This (force pairs) (force leftover)++-- Benchmark groups+main :: IO ()+main = defaultMain+  [ alignBenchmarks+  , unalignBenchmarks+  , roundtripBenchmarks+  , transformationBenchmarks+  , fusionBenchmarks+  ]++-- | Benchmark align vs zip for different sizes and structures+alignBenchmarks :: Benchmark+alignBenchmarks = bgroup "align vs zip"+  [ bgroup "lists"+      [ bgroup "equal length"+          [ bench "zip 100" $ nf (uncurry zip) (listPair 100)+          , bench "align 100" $ nf (uncurry alignList) (listPair 100)+          , bench "zip 1000" $ nf (uncurry zip) (listPair 1000)+          , bench "align 1000" $ nf (uncurry alignList) (listPair 1000)+          , bench "zip 10000" $ nf (uncurry zip) (listPair 10000)+          , bench "align 10000" $ nf (uncurry alignList) (listPair 10000)+          ]+      , bgroup "unequal length"+          [ bench "zip 100/50" $ nf (\(xs, ys) -> zip xs (take 50 ys)) (listPair 100)+          , bench "align 100/50" $ nf (\(xs, ys) -> alignList xs (take 50 ys)) (listPair 100)+          , bench "zip 1000/500" $ nf (\(xs, ys) -> zip xs (take 500 ys)) (listPair 1000)+          , bench "align 1000/500" $ nf (\(xs, ys) -> alignList xs (take 500 ys)) (listPair 1000)+          ]+      ]+  , bgroup "vectors"+      [ bgroup "equal length"+          [ bench "zip 100" $ nf (uncurry V.zip) (vectorPair 100)+          , bench "align 100" $ nf (uncurry alignVec) (vectorPair 100)+          , bench "zip 1000" $ nf (uncurry V.zip) (vectorPair 1000)+          , bench "align 1000" $ nf (uncurry alignVec) (vectorPair 1000)+          , bench "zip 10000" $ nf (uncurry V.zip) (vectorPair 10000)+          , bench "align 10000" $ nf (uncurry alignVec) (vectorPair 10000)+          ]+      ]+  , bgroup "NonEmpty"+      [ bench "align 100" $ nf (uncurry alignNE) (nePair 100)+      , bench "align 1000" $ nf (uncurry alignNE) (nePair 1000)+      ]+  ]+  where+    alignList :: [Int] -> [Int] -> This [] NonEmpty Int Int+    alignList = align+    alignVec :: V.Vector Int -> V.Vector Int -> This V.Vector NonEmpty Int Int+    alignVec = align+    alignNE :: NonEmpty Int -> NonEmpty Int -> This NonEmpty NonEmpty Int Int+    alignNE = align++-- | Benchmark unalign vs unzip+unalignBenchmarks :: Benchmark+unalignBenchmarks = bgroup "unalign vs unzip"+  [ bgroup "lists"+      [ bench "unzip 100" $ nf unzip (pairList 100)+      , bench "unalign 100" $ nf unalignList (alignedList 100)+      , bench "unzip 1000" $ nf unzip (pairList 1000)+      , bench "unalign 1000" $ nf unalignList (alignedList 1000)+      , bench "unzip 10000" $ nf unzip (pairList 10000)+      , bench "unalign 10000" $ nf unalignList (alignedList 10000)+      ]+  , bgroup "vectors"+      [ bench "unzip 100" $ nf V.unzip (V.fromList $ pairList 100)+      , bench "unalign 100" $ nf unalignVec (alignedVector 100)+      , bench "unzip 1000" $ nf V.unzip (V.fromList $ pairList 1000)+      , bench "unalign 1000" $ nf unalignVec (alignedVector 1000)+      , bench "unzip 10000" $ nf V.unzip (V.fromList $ pairList 10000)+      , bench "unalign 10000" $ nf unalignVec (alignedVector 10000)+      ]+  ]+  where+    unalignList :: This [] NonEmpty Int Int -> ([Int], [Int])+    unalignList = unalign+    unalignVec :: This V.Vector NonEmpty Int Int -> (V.Vector Int, V.Vector Int)+    unalignVec = unalign++-- | Benchmark roundtrip: align then unalign+roundtripBenchmarks :: Benchmark+roundtripBenchmarks = bgroup "roundtrip"+  [ bgroup "lists"+      [ bench "zip/unzip 100" $ nf (\(xs, ys) -> unzip (zip xs ys)) (listPair 100)+      , bench "align/unalign 100" $ nf (\(xs, ys) -> unalign (align xs ys :: This [] NonEmpty Int Int)) (listPair 100)+      , bench "zip/unzip 1000" $ nf (\(xs, ys) -> unzip (zip xs ys)) (listPair 1000)+      , bench "align/unalign 1000" $ nf (\(xs, ys) -> unalign (align xs ys :: This [] NonEmpty Int Int)) (listPair 1000)+      ]+  , bgroup "vectors"+      [ bench "zip/unzip 100" $ nf (\(xs, ys) -> V.unzip (V.zip xs ys)) (vectorPair 100)+      , bench "align/unalign 100" $ nf (\(xs, ys) -> unalign (align xs ys :: This V.Vector NonEmpty Int Int)) (vectorPair 100)+      , bench "zip/unzip 1000" $ nf (\(xs, ys) -> V.unzip (V.zip xs ys)) (vectorPair 1000)+      , bench "align/unalign 1000" $ nf (\(xs, ys) -> unalign (align xs ys :: This V.Vector NonEmpty Int Int)) (vectorPair 1000)+      ]+  ]++-- | Benchmark transformation operations (map during align/unalign)+transformationBenchmarks :: Benchmark+transformationBenchmarks = bgroup "with transformation"+  [ bgroup "lists"+      [ bench "map/zip/map 1000" $ nf (\(xs, ys) -> let zs = zip xs ys in (map ((+1) . fst) zs, map ((*2) . snd) zs)) (listPair 1000)+      , bench "alignWith 1000" $ nf (\(xs, ys) -> alignWith id (+1) (*2) xs ys :: This [] NonEmpty Int Int) (listPair 1000)+      , bench "unzip/map/map 1000" $ nf (bimap (map (+1)) (map (*2)) . unzip) (pairList 1000)+      , bench "unalignWith 1000" $ nf (unalignWith (+1) (*2)) (alignedList 1000)+      ]+  ]++-- | Benchmark fusion effectiveness+fusionBenchmarks :: Benchmark+fusionBenchmarks = bgroup "fusion"+  [ bgroup "composition"+      -- These benchmarks intentionally compare unoptimized vs optimized forms+      {- HLINT ignore "Functor law" -}+      {- HLINT ignore "Redundant bimap" -}+      [ bench "fmap . fmap 1000" $ nf (fmap (*2) . fmap (+1)) (alignedList 1000)+      , bench "fmap composed 1000" $ nf (fmap ((*2) . (+1))) (alignedList 1000)+      , bench "bimap . bimap 1000" $ nf (bimap (*2) (*3) . bimap (+1) (+2)) (alignedList 1000)+      , bench "bimap composed 1000" $ nf (bimap ((*2) . (+1)) ((*3) . (+2))) (alignedList 1000)+      ]+  , bgroup "roundtrip elimination"+      [ bench "align/unalign 1000" $ nf (\(xs, ys) -> unalign (align xs ys :: This [] NonEmpty Int Int)) (listPair 1000)+      , bench "direct 1000" $ nf id (listPair 1000)+      , bench "alignWith/unalignWith 1000" $ nf (\(xs, ys) -> unalignWith (+1) (*2) (align xs ys :: This [] NonEmpty Int Int)) (listPair 1000)+      , bench "map/map 1000" $ nf (bimap (map (+1)) (map (*2))) (listPair 1000)+      ]+  ]++-- Test data generators+listPair :: Int -> ([Int], [Int])+listPair n = ([1..n], [1..n])++vectorPair :: Int -> (V.Vector Int, V.Vector Int)+vectorPair n = (V.enumFromN 1 n, V.enumFromN 1 n)++nePair :: Int -> (NonEmpty Int, NonEmpty Int)+nePair n = (1 :| [2..n], 1 :| [2..n])++pairList :: Int -> [(Int, Int)]+pairList n = [(i, i) | i <- [1..n]]++alignedList :: Int -> This [] NonEmpty Int Int+alignedList n = align [1..n] [1..n]++alignedVector :: Int -> This V.Vector NonEmpty Int Int+alignedVector n = align (V.enumFromN 1 n) (V.enumFromN 1 n)
changelog.md view
@@ -1,3 +1,34 @@+0.2.0.0 (2026-05-19)++* Add `Unalign` type class for recovering original functors from alignment+* Add `aligned` isomorphism to Unalign, witnessing that alignment is lossless+* Add `unaligned` isomorphism, the inverse of `aligned`+* Add `unalignWith` method to Unalign, the dual of `alignWith` for transformation during unalignment+* Add `Unalign` instances for Identity, [], Maybe, NonEmpty, ZipList, Seq, Vector+* Add `NFData` instance for This (enables criterion benchmarking)+* Note: Map and IntMap deliberately excluded from Unalign to maintain law compliance+* Add comprehensive law documentation for Semialign, Align, and Unalign type classes+* Add testable law-checking functions: `semialignNaturality`, `semialignSymmetry`,+  `semialignCoherence`, `semialignWithLaw`, `alignRightIdentity`, `alignLeftIdentity`,+  `alignEmpty`, `unalignRoundtrip`, `unalignNaturality`+* Add 12 RULES pragmas for fusion optimization:+  - Semialign fusion: `semialign/naturality`, `alignWith/bimap`, `align/swap/symmetry`, `fmap/as/bimap`+  - Unalign fusion: `unalign/align/roundtrip`, `unalign/bimap/naturality`, `unalignWith/align`+  - Functor/Bifunctor composition: `fmap/fmap/This`, `bimap/bimap/This`+  - Swap optimization: `swap/swap/This`, `swap/bimap/This`, `bimap/swap/This`+* Add 56 INLINE/INLINABLE pragmas for comprehensive optimization:+  - All type class method defaults marked INLINE+  - All Semialign instances marked INLINE or INLINABLE+  - All Align nil methods marked INLINE+  - All Unalign instances marked INLINE or INLINABLE+  - All lens/traversal/fold functions marked INLINE or INLINABLE+  - Strategic use of INLINE for small wrappers, INLINABLE for recursive/larger functions+* Add FUSION.md documenting fusion rules and performance characteristics+* Add comprehensive criterion benchmark suite comparing to zip/unzip+* Reorganize all Semialign instances to be consecutive for better code navigation+* Expand README with examples, comparisons, and usage guide+* Improve cabal file description+ 0.1.0.6  * Fix URLs in cabal file
src/Data/Alignment.hs view
@@ -1,681 +1,1619 @@-{-# OPTIONS_GHC -Wall #-}-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE FlexibleInstances #-}-{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}-{-# HLINT ignore "Use fmap" #-}--module Data.Alignment(--- * Types-  This(..)--- * Type-classes-, Semialign(..)-, Align(..)--- * Optics-, these-, those-, allThese-, allThese1-, allThese2-, allThose-, allThoseA-, allThoseAOr-, allThoseB-, allThoseBOr-, allTheseThoseA-, allTheseThoseA1-, allTheseThoseB-, allTheseThoseB1-) where--import Control.Applicative-    ( Applicative(liftA2, pure, (<*>)), (<$>), ZipList(ZipList) )-import Control.Category ( Category((.), id) )-import Control.Lens-    ( Identity(Identity),-      _Just,-      _Left,-      _Right,-      over,-      Field1(_1),-      Field2(_2),-      Lens,-      Lens',-      Traversal,-      Traversal',-      Traversal1 )-import Data.Bifoldable ( Bifoldable(bifoldMap) )-import Data.Bifunctor ( Bifunctor(bimap) )-import Data.Bifunctor.Swap ( Swap(..) )-import Data.Bitraversable ( Bitraversable(..) )-import Data.List.NonEmpty ( NonEmpty(..) )-import Data.Bool ( (&&) )-import Data.Either ( Either(..), either )-import Data.Eq ( Eq((==)) )-import Data.Foldable ( Foldable(foldMap) )-import Data.Functor ( Functor(fmap), (<$) )-import Data.Functor.Apply ( Apply((<.>), liftF2) )-import Data.Functor.Classes-    ( compare1,-      eq1,-      showsPrec1,-      showsUnaryWith,-      Eq1(..),-      Ord1(..),-      Show1(..) )-import qualified Data.List.NonEmpty as NonEmpty(cons, toList)-import Data.Maybe ( Maybe(..), maybe )-import Data.Monoid ( (<>), Monoid(mempty) )-import Data.Ord ( Ord(compare) )-import Data.Semigroup ( Semigroup )-import Data.Semigroup.Bifoldable ( Bifoldable1(bifoldMap1) )-import Data.Semigroup.Bitraversable ( Bitraversable1(bitraverse1) )-import Data.Semigroup.Foldable ( Foldable1(foldMap1) )-import Data.Semigroup.Traversable ( Traversable1(traverse1) )-import Data.Traversable ( Traversable(traverse) )-import GHC.Show ( Show(showsPrec) )---- $setup--- >>> import Prelude--data This f a b =-  This-    (f (a, b))-    (Maybe (Either (NonEmpty a) (NonEmpty b)))--instance (Eq1 f, Eq a, Eq b) => Eq (This f a b) where-  This t1 r1 == This t2 r2 =-    t1 `eq1` t2 && r1 == r2--instance (Eq1 f, Eq a) => Eq1 (This f a) where-  liftEq f (This t1 r1) (This t2 r2) =-    liftEq (liftEq f) t1 t2 && liftEq (liftEq (liftEq f)) r1 r2--instance (Ord1 f, Ord a, Ord b) => Ord (This f a b) where-  This t1 r1 `compare` This t2 r2 =-    t1 `compare1` t2 <> r1 `compare` r2--instance (Ord1 f, Ord a) => Ord1 (This f a) where-  liftCompare f (This t1 r1) (This t2 r2) =-    liftCompare (liftCompare f) t1 t2 <> liftCompare (liftCompare (liftCompare f)) r1 r2--instance (Show1 f, Show a, Show b) => Show (This f a b) where-  showsPrec d (This t r) =-    showsUnaryWith showsPrec1 "This" d t . (" " <>) . showsPrec1 d r--instance (Show1 f, Show a) => Show1 (This f a) where-  liftShowsPrec sp sl d (This t r) =-    let showsPrecFt = liftShowsPrec (liftShowsPrec sp sl) (liftShowList sp sl)-        showsPrecFr = liftShowsPrec (liftShowsPrec (liftShowsPrec sp sl) (liftShowList sp sl)) (liftShowList (liftShowsPrec sp sl) (liftShowList sp sl))-    in  showsUnaryWith showsPrecFt "This" d t . (" " <>) . showsPrecFr d r--instance Functor f => Bifunctor (This f) where-  bimap f g (This t r) =-    This (fmap (bimap f g) t) (fmap (bimap (fmap f) (fmap g)) r)--instance Foldable f => Bifoldable (This f) where-  bifoldMap f g (This t r) =-    foldMap (bifoldMap f g) t <> foldMap (bifoldMap (foldMap f) (foldMap g)) r--instance Foldable1 f => Bifoldable1 (This f) where-  bifoldMap1 f g (This t r) =-    let x =-          foldMap1 (bifoldMap1 f g) t-    in  maybe x (either (foldMap1 f) (foldMap1 g)) r--instance Traversable f => Bitraversable (This f) where-  bitraverse f g (This t r) =-    This <$> traverse (bitraverse f g) t <*> traverse (bitraverse (traverse f) (traverse g)) r--instance Traversable1 f => Bitraversable1 (This f) where-  bitraverse1 f g (This t r) =-    let x =-          This <$> traverse1 (bitraverse1 f g) t-    in  maybe-          ((\k -> k Nothing) <$> x)-          (\q -> x <.> either (fmap (Just . Left) . traverse1 f) (fmap (Just . Right) . traverse1 g) q)-          r--instance Functor f => Functor (This f a) where-  fmap =-    bimap id---- |------ >>> This [("a", id), ("c", id)] Nothing <.> This [("A", "B"), ("C", "D")] Nothing--- This [("aA","B"),("aC","D"),("cA","B"),("cC","D")] Nothing--- >>> This [("a", id), ("c", id)] Nothing <.> This [("A", "B"), ("C", "D")] (Just (Left ("x":|[])))--- This [("aA","B"),("aC","D"),("cA","B"),("cC","D")] Nothing--- >>> This [("abc", reverse), ("cde", reverse)] Nothing <.> This [("ABC", "DEF"), ("GHI", "JKL")] Nothing--- This [("abcABC","FED"),("abcGHI","LKJ"),("cdeABC","FED"),("cdeGHI","LKJ")] Nothing--- >>> This [("abc", reverse), ("cde", reverse)] Nothing <.> This [("ABC", "DEF"), ("GHI", "JKL")] (Just (Left ("xyz":|[])))--- This [("abcABC","FED"),("abcGHI","LKJ"),("cdeABC","FED"),("cdeGHI","LKJ")] Nothing--- >>> This [("abc", reverse), ("cde", reverse)] Nothing <.> This [("ABC", "DEF"), ("GHI", "JKL")] (Just (Right ("xyz":|[])))--- This [("abcABC","FED"),("abcGHI","LKJ"),("cdeABC","FED"),("cdeGHI","LKJ")] Nothing--- >>> This [("abc", reverse), ("cde", reverse)] (Just (Left ("stu":|[]))) <.> This [("ABC", "DEF"), ("GHI", "JKL")] Nothing--- This [("abcABC","FED"),("abcGHI","LKJ"),("cdeABC","FED"),("cdeGHI","LKJ")] Nothing--- >>> This [("abc", reverse), ("cde", reverse)] (Just (Right (id:|[reverse]))) <.> This [("ABC", "DEF"), ("GHI", "JKL")] Nothing--- This [("abcABC","FED"),("abcGHI","LKJ"),("cdeABC","FED"),("cdeGHI","LKJ")] Nothing--- >>> This [("abc", reverse), ("cde", reverse)] (Just (Left ("stu":|[]))) <.> This [("ABC", "DEF"), ("GHI", "JKL")] (Just (Left ("xyz":|[])))--- This [("abcABC","FED"),("abcGHI","LKJ"),("cdeABC","FED"),("cdeGHI","LKJ")] Just (Left ("stu" :| []))--- >>> This [("abc", reverse), ("cde", reverse)] (Just (Left ("stu":|[]))) <.> This [("ABC", "DEF"), ("GHI", "JKL")] (Just (Right ("xyz":|[])))--- This [("abcABC","FED"),("abcGHI","LKJ"),("cdeABC","FED"),("cdeGHI","LKJ")] Just (Left ("stu" :| []))--- >>> This [("abc", reverse), ("cde", reverse)] (Just (Right (id:|[reverse]))) <.> This [("ABC", "DEF"), ("GHI", "JKL")] (Just (Left ("xyz":|[])))--- This [("abcABC","FED"),("abcGHI","LKJ"),("cdeABC","FED"),("cdeGHI","LKJ")] Just (Left ("xyz" :| []))--- >>> This [("abc", reverse), ("cde", reverse)] (Just (Left ("stu":|[]))) <.> This [("ABC", "DEF"), ("GHI", "JKL")] (Just (Right ("xyz":|[])))--- This [("abcABC","FED"),("abcGHI","LKJ"),("cdeABC","FED"),("cdeGHI","LKJ")] Just (Left ("stu" :| []))-instance (Semigroup a, Apply f) => Apply (This f a) where-  This t1 r1 <.> This t2 r2 =-    This (liftF2 (<.>) t1 t2) (liftF2 (liftF2 (<.>)) r1 r2)--instance (Monoid a, Applicative f) => Applicative (This f a) where-  pure a =-    This (pure (mempty, a)) (pure (pure (pure a)))-  This t1 r1 <*> This t2 r2 =-    This (liftA2 (<*>) t1 t2) (liftF2 (liftF2 (<*>)) r1 r2)---- |------ >>> swap (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [('x',"abc"),('y',"def")] Nothing--- >>> swap (This [("abc", 'x'), ("def", 'y')] (Just (Left ("a":|[]))))--- This [('x',"abc"),('y',"def")] Just (Right ("a" :| []))--- >>> swap (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|[]))))--- This [('x',"abc"),('y',"def")] Just (Left ('a' :| ""))-instance Functor f => Swap (This f) where-  swap (This t r) =-    This (fmap swap t) (fmap swap r)--class Functor f => Semialign f where-  align ::-    f a-    -> f b-    -> This f a b-  align =-    alignWith id id id-  alignWith ::-    ((a, b) -> (c, d))-    -> (a -> c)-    -> (b -> d)-    -> f a-    -> f b-    -> This f c d-  alignWith f g h t1 t2 =-    case align t1 t2 of-      This t r ->-        This (fmap f t) (fmap (bimap (fmap g) (fmap h)) r)-  {-# MINIMAL align | alignWith #-}-  alignWith' ::-    (a -> c)-    -> (b -> d)-    -> f a-    -> f b-    -> This f c d-  alignWith' f g =-    alignWith (bimap f g) f g---- |------ >>> align "abc" "def"--- This [('a','d'),('b','e'),('c','f')] Nothing--- >>> align "abc" "defghi"--- This [('a','d'),('b','e'),('c','f')] Just (Right ('g' :| "hi"))--- >>> align "abcdef" "ghi"--- This [('a','g'),('b','h'),('c','i')] Just (Left ('d' :| "ef"))-instance Semialign [] where-  align (a:as) (b:bs) =-    let This t r = align as bs-    in  This ((a,b):t) r-  align (a:as) [] =-    This [] (Just (Left (a :| as)))-  align [] (b:bs) =-    This [] (Just (Right (b :| bs)))-  align [] [] =-    This [] Nothing---- |------ >>> align (Just "x") (Just "y")--- This (Just ("x","y")) Nothing--- >>> align (Just "x") (Nothing :: Maybe String)--- This Nothing Just (Left ("x" :| []))--- >>> align (Nothing :: Maybe String) (Just "y")--- This Nothing Just (Right ("y" :| []))-instance Semialign Maybe where-  align (Just a) (Just b) =-    This (Just (a, b)) Nothing-  align (Just a) Nothing =-    This Nothing (Just (Left (a :| [])))-  align Nothing (Just b) =-    This Nothing (Just (Right (b :| [])))-  align Nothing Nothing =-    This Nothing Nothing---- |------ >>> align (Identity "x") (Identity "y")--- This (Identity ("x","y")) Nothing-instance Semialign Identity where-  align (Identity a) (Identity b) =-    This (Identity (a, b)) Nothing---- |------ >>> align ('a':|"bc") ('g':|"hi")--- This (('a','g') :| [('b','h'),('c','i')]) Nothing--- >>> align ('a':|"bc") ('g':|"hijkl")--- This (('a','g') :| [('b','h'),('c','i')]) Just (Right ('j' :| "kl"))--- >>> align ('a':|"bcdef") ('g':|"hi")--- This (('a','g') :| [('b','h'),('c','i')]) Just (Left ('d' :| "ef"))-instance Semialign NonEmpty where-  align (h1:|[]) (h2:|[]) =-    This ((h1, h2):|[]) Nothing-  align (h1:|i1:r1) (h2:|[]) =-    This ((h1, h2):|[]) (Just (Left (i1:|r1)))-  align (h1:|[]) (h2:|i2:r2) =-    This ((h1, h2):|[]) (Just (Right (i2:|r2)))-  align (h1:|i1:r1) (h2:|i2:r2) =-    let This t r = align (i1:|r1) (i2:|r2)-    in  This ((h1, h2) `NonEmpty.cons` t) r--instance Semialign ZipList where-  align (ZipList a) (ZipList b) =-    over these ZipList (align a b)--class Semialign f => Align f where-  nil ::-    f a--instance Align [] where-  nil =-    []--instance Align Maybe where-  nil =-    Nothing--instance Align ZipList where-  nil =-    ZipList []---- |------ >>> This [("abc", 's'), ("def", 't')] Nothing <> This [("ghi", 'u'), ("jkl", 'v')] Nothing--- This [("abc",'s'),("def",'t'),("ghi",'u'),("jkl",'v')] Nothing--- >>> This [("abc", 's'), ("def", 't')] Nothing <> This [("ghi", 'u'), ("jkl", 'v')] (Just (Left ("mno":|["pqr"])))--- This [("abc",'s'),("def",'t'),("ghi",'u'),("jkl",'v')] Just (Left ("mno" :| ["pqr"]))--- >>> This [("abc", 's'), ("def", 't')] Nothing <> This [("ghi", 'u'), ("jkl", 'v')] (Just (Right ('o':|"pqr")))--- This [("abc",'s'),("def",'t'),("ghi",'u'),("jkl",'v')] Just (Right ('o' :| "pqr"))--- >>> This [("abc", 's'), ("def", 't')] (Just (Left ("mno":|["pqr"]))) <> This [("ghi", 'u'), ("jkl", 'v')] Nothing--- This [("abc",'s'),("def",'t'),("ghi",'u'),("jkl",'v')] Just (Left ("mno" :| ["pqr"]))--- >>> This [("abc", 's'), ("def", 't')] (Just (Right ('o':|"pqr"))) <> This [("ghi", 'u'), ("jkl", 'v')] Nothing--- This [("abc",'s'),("def",'t'),("ghi",'u'),("jkl",'v')] Just (Right ('o' :| "pqr"))--- >>> This [("abc", 's'), ("def", 't')] (Just (Left ("mno":|["pqr"]))) <> This [("ghi", 'u'), ("jkl", 'v')] (Just (Left ("ccddee":|["ffgghh"])))--- This [("abc",'s'),("def",'t'),("ghi",'u'),("jkl",'v')] Just (Left ("mno" :| ["pqr","ccddee","ffgghh"]))--- >>> This [("abc", 's'), ("def", 't')] (Just (Left ("mno":|["pqr"]))) <> This [("ghi", 'u'), ("jkl", 'v')] (Just (Right ('c':|"ddeeff")))--- This [("abc",'s'),("def",'t'),("ghi",'u'),("jkl",'v'),("mno",'c'),("pqr",'d')] Just (Right ('d' :| "eeff"))--- >>> This [("abc", 's'), ("def", 't')] (Just (Right ('x':|"yyzz"))) <> This [("ghi", 'u'), ("jkl", 'v')] (Just (Right ('c':|"ddeeff")))--- This [("abc",'s'),("def",'t'),("ghi",'u'),("jkl",'v')] Just (Right ('x' :| "yyzzcddeeff"))--- >>> This [("abc", 's'), ("def", 't')] (Just (Right ('x':|"yyzz"))) <> This [("ghi", 'u'), ("jkl", 'v')] (Just (Left ("cc":|["ddeeff"])))--- This [("abc",'s'),("def",'t'),("ghi",'u'),("jkl",'v'),("cc",'x'),("ddeeff",'y')] Just (Right ('y' :| "zz"))-instance Semigroup (This [] a b) where-  This t1 (Just (Left as1)) <> This t2 (Just (Left as2)) =-    This (t1 <> t2) (Just (Left (as1 <> as2)))-  This t1 (Just (Left as1)) <> This t2 (Just (Right bs2)) =-    over these (\x -> t1 <> t2 <> NonEmpty.toList x) (align as1 bs2)-  This t1 (Just (Left as1)) <> This t2 Nothing =-    This (t1 <> t2) (Just (Left as1))-  This t1 (Just (Right bs1)) <> This t2 (Just (Right bs2)) =-    This (t1 <> t2) (Just (Right (bs1 <> bs2)))-  This t1 (Just (Right bs1)) <> This t2 (Just (Left as2)) =-    over these (\x -> t1 <> t2 <> NonEmpty.toList x) (align as2 bs1)-  This t1 (Just (Right bs1)) <> This t2 Nothing =-    This (t1 <> t2) (Just (Right bs1))-  This t1 Nothing <> This t2 (Just (Left as2)) =-    This (t1 <> t2) (Just (Left as2))-  This t1 Nothing <> This t2 (Just (Right bs2)) =-    This (t1 <> t2) (Just (Right bs2))-  This t1 Nothing <> This t2 Nothing =-    This (t1 <> t2) Nothing--instance Semigroup (This NonEmpty a b) where-  This t1 (Just (Left as1)) <> This t2 (Just (Left as2)) =-    This (t1 <> t2) (Just (Left (as1 <> as2)))-  This t1 (Just (Left as1)) <> This t2 (Just (Right bs2)) =-    over these (\x -> t1 <> t2 <> x) (align as1 bs2)-  This t1 (Just (Left as1)) <> This t2 Nothing =-    This (t1 <> t2) (Just (Left as1))-  This t1 (Just (Right bs1)) <> This t2 (Just (Right bs2)) =-    This (t1 <> t2) (Just (Right (bs1 <> bs2)))-  This t1 (Just (Right bs1)) <> This t2 (Just (Left as2)) =-    over these (\x -> t1 <> t2 <> x) (align as2 bs1)-  This t1 (Just (Right bs1)) <> This t2 Nothing =-    This (t1 <> t2) (Just (Right bs1))-  This t1 Nothing <> This t2 (Just (Left as2)) =-    This (t1 <> t2) (Just (Left as2))-  This t1 Nothing <> This t2 (Just (Right bs2)) =-    This (t1 <> t2) (Just (Right bs2))-  This t1 Nothing <> This t2 Nothing =-    This (t1 <> t2) Nothing--instance Monoid (This [] a b) where-  mempty =-    This mempty Nothing---- |------ >>> over these reverse (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("def",'y'),("abc",'x')] Nothing--- >>> over these reverse (This [("abc", 'x'), ("def", 'y')] (Just (Left ("ghi":|["jkl"]))))--- This [("def",'y'),("abc",'x')] Just (Left ("ghi" :| ["jkl"]))-these ::-  Lens-    (This f a b)-    (This f' a b)-    (f (a, b))-    (f' (a, b))-these f (This t r) =-  fmap (`This` r) (f t)---- |------ >>> over those (fmap (bimap (fmap reverse) (fmap Data.Char.toUpper))) (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("abc",'x'),("def",'y')] Nothing--- >>> over those (fmap (bimap (fmap reverse) (fmap Data.Char.toUpper))) (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("abc",'x'),("def",'y')] Just (Left ("cba" :| ["fed"]))--- >>> over those (fmap (bimap (fmap reverse) (fmap Data.Char.toUpper))) (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("abc",'x'),("def",'y')] Just (Right ('A' :| "BCDE"))--- >>> Control.Lens.view those (This [("abc", 'x'), ("def", 'y')] Nothing)--- Nothing--- >>> Control.Lens.view those (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Just (Left ("abc" :| ["def"]))--- >>> Control.Lens.view those (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Just (Right ('a' :| "bcde"))-those ::-  Lens'-    (This f a b)-    (Maybe (Either (NonEmpty a) (NonEmpty b)))-those f (This t r) =-  fmap (This t) (f r)---- |------ >>> over allThese (bimap reverse Data.Char.toUpper) (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("cba",'X'),("fed",'Y')] Nothing--- >>> over allThese (bimap reverse Data.Char.toUpper) (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("cba",'X'),("fed",'Y')] Just (Left ("abc" :| ["def"]))--- >>> over allThese (bimap reverse Data.Char.toUpper) (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("cba",'X'),("fed",'Y')] Just (Right ('a' :| "bcde"))--- >>> Control.Lens.preview allThese (This [("abc", 'x'), ("def", 'y')] Nothing)--- Just ("abc",'x')--- >>> Control.Lens.preview allThese (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Just ("abc",'x')--- >>> Control.Lens.preview allThese (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Just ("abc",'x')-allThese ::-  Traversable f =>-  Traversal'-    (This f a b)-    (a, b)-allThese =-  these . traverse---- |------ >>> over allThese1 reverse (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("cba",'x'),("fed",'y')] Nothing--- >>> over allThese1 reverse (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("cba",'x'),("fed",'y')] Just (Left ("abc" :| ["def"]))--- >>> over allThese1 reverse (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("cba",'x'),("fed",'y')] Just (Right ('a' :| "bcde"))--- >>> Control.Lens.preview allThese1 (This [("abc", 'x'), ("def", 'y')] Nothing)--- Just "abc"--- >>> Control.Lens.preview allThese1 (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Just "abc"--- >>> Control.Lens.preview allThese1 (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Just "abc"-allThese1 ::-  Traversable f =>-  Traversal'-    (This f a b)-    a-allThese1 =-  allThese . _1---- |------ >>> over allThese2 Data.Char.toUpper (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("abc",'X'),("def",'Y')] Nothing--- >>> over allThese2 Data.Char.toUpper (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("abc",'X'),("def",'Y')] Just (Left ("abc" :| ["def"]))--- >>> over allThese2 Data.Char.toUpper (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("abc",'X'),("def",'Y')] Just (Right ('a' :| "bcde"))--- >>> Control.Lens.preview allThese2 (This [("abc", 'x'), ("def", 'y')] Nothing)--- Just 'x'--- >>> Control.Lens.preview allThese2 (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Just 'x'--- >>> Control.Lens.preview allThese2 (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Just 'x'-allThese2 ::-  Traversable f =>-  Traversal'-    (This f a b)-    b-allThese2 =-  allThese . _2---- |------ >>> over allThose (bimap (fmap reverse) (fmap Data.Char.toUpper)) (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("abc",'x'),("def",'y')] Nothing--- >>> over allThose (bimap (fmap reverse) (fmap Data.Char.toUpper)) (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("abc",'x'),("def",'y')] Just (Left ("cba" :| ["fed"]))--- >>> over allThose (bimap (fmap reverse) (fmap Data.Char.toUpper)) (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("abc",'x'),("def",'y')] Just (Right ('A' :| "BCDE"))--- >>> Control.Lens.preview allThose (This [("abc", 'x'), ("def", 'y')] Nothing)--- Nothing--- >>> Control.Lens.preview allThose (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Just (Left ("abc" :| ["def"]))--- >>> Control.Lens.preview allThose (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Just (Right ('a' :| "bcde"))-allThose ::-  Traversal'-    (This f a b)-    (Either (NonEmpty a) (NonEmpty b))-allThose =-  those . _Just---- |------ >>> over allThoseA (fmap reverse) (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("abc",'x'),("def",'y')] Nothing--- >>> over allThoseA (fmap reverse) (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("abc",'x'),("def",'y')] Just (Left ("cba" :| ["fed"]))--- >>> over allThoseA (fmap reverse) (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("abc",'x'),("def",'y')] Just (Right ('a' :| "bcde"))--- >>> Control.Lens.preview allThoseA (This [("abc", 'x'), ("def", 'y')] Nothing)--- Nothing--- >>> Control.Lens.preview allThoseA (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Just ("abc" :| ["def"])--- >>> Control.Lens.preview allThoseA (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Nothing-allThoseA ::-  Traversal'-    (This f a b)-    (NonEmpty a)-allThoseA =-  allThose . _Left---- |------ >>> over allThoseAOr reverse (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("abc",'x'),("def",'y')] Nothing--- >>> over allThoseAOr reverse (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("abc",'x'),("def",'y')] Just (Left ("def" :| ["abc"]))--- >>> over allThoseAOr reverse (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("abc",'x'),("def",'y')] Just (Right ('a' :| "bcde"))--- >>> Control.Lens.preview allThoseAOr (This [("abc", 'x'), ("def", 'y')] Nothing)--- Just []--- >>> Control.Lens.preview allThoseAOr (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Just ["abc","def"]--- >>> Control.Lens.preview allThoseAOr (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Nothing-allThoseAOr ::-  Traversal'-    (This f a b)-    [a]-allThoseAOr f (This t Nothing) =-  This t <$> (Nothing <$ f [])-allThoseAOr _ th@(This _ (Just (Right _))) =-  pure th-allThoseAOr f (This t (Just (Left a))) =-  let lst [] = Nothing-      lst (x:y) = Just (x:|y)-  in  This t . fmap Left . lst <$> f (NonEmpty.toList a)---- |------ >>> over allThoseB (fmap Data.Char.toUpper) (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("abc",'x'),("def",'y')] Nothing--- >>> over allThoseB (fmap Data.Char.toUpper) (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("abc",'x'),("def",'y')] Just (Left ("abc" :| ["def"]))--- >>> over allThoseB (fmap Data.Char.toUpper) (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("abc",'x'),("def",'y')] Just (Right ('A' :| "BCDE"))--- >>> Control.Lens.preview allThoseB (This [("abc", 'x'), ("def", 'y')] Nothing)--- Nothing--- >>> Control.Lens.preview allThoseB (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Nothing--- >>> Control.Lens.preview allThoseB (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Just ('a' :| "bcde")-allThoseB ::-  Traversal'-    (This f a b)-    (NonEmpty b)-allThoseB =-  allThose . _Right---- |------ >>> over allThoseBOr reverse (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("abc",'x'),("def",'y')] Nothing--- >>> over allThoseBOr reverse (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("abc",'x'),("def",'y')] Just (Left ("abc" :| ["def"]))--- >>> over allThoseBOr reverse (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("abc",'x'),("def",'y')] Just (Right ('e' :| "dcba"))--- >>> Control.Lens.preview allThoseBOr (This [("abc", 'x'), ("def", 'y')] Nothing)--- Just ""--- >>> Control.Lens.preview allThoseBOr (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Nothing--- >>> Control.Lens.preview allThoseBOr (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Just "abcde"-allThoseBOr ::-  Traversal'-    (This f a b)-    [b]-allThoseBOr f (This t Nothing) =-  This t <$> (Nothing <$ f [])-allThoseBOr f (This t (Just (Right b))) =-  let lst [] = Nothing-      lst (x:y) = Just (x:|y)-  in  This t . fmap Right . lst <$> f (NonEmpty.toList b)-allThoseBOr _ th@(This _ (Just (Left _))) =-  pure th---- |------ >>> over allTheseThoseA (fmap Data.Char.toUpper) (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("ABC",'x'),("DEF",'y')] Nothing--- >>> over allTheseThoseA (fmap Data.Char.toUpper) (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("ABC",'x'),("DEF",'y')] Just (Left ("ABC" :| ["DEF"]))--- >>> over allTheseThoseA (fmap Data.Char.toUpper) (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("ABC",'x'),("DEF",'y')] Just (Right ('a' :| "bcde"))--- >>> Control.Lens.preview allTheseThoseA (This [("abc", 'x'), ("def", 'y')] Nothing)--- Just "abc"--- >>> Control.Lens.preview allTheseThoseA (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Just "abc"--- >>> Control.Lens.preview allTheseThoseA (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Just "abc"-allTheseThoseA ::-  Traversable f =>-  Traversal-    (This f a b)-    (This f a' b)-    a-    a'-allTheseThoseA f (This t r) =-  let th =-        case r of-          Nothing ->-            pure Nothing-          Just (Left as) ->-            Just . Left <$> traverse f as-          Just (Right bs) ->-            pure (Just (Right bs))-  in  This <$>-        traverse (\(a, b) -> (, b) <$> f a) t <*> th--allTheseThoseA1 ::-  Traversable1 f =>-  Traversal1-    (This f a b)-    (This f a' b)-    a-    a'-allTheseThoseA1 f (This t r) =-  let x = This <$> traverse1 (\(a, b) -> (, b) <$> f a) t-  in  maybe-        ((\k -> k Nothing) <$> x)-        (-          either-            ((\p -> (\k -> k . Just . Left) <$> x <.> p) . traverse1 f)-             (\z -> (\k -> k (Just (Right z))) <$> x))-        r---- |------ >>> over allTheseThoseB Data.Char.toUpper (This [("abc", 'x'), ("def", 'y')] Nothing)--- This [("abc",'X'),("def",'Y')] Nothing--- >>> over allTheseThoseB Data.Char.toUpper (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- This [("abc",'X'),("def",'Y')] Just (Left ("abc" :| ["def"]))--- >>> over allTheseThoseB Data.Char.toUpper (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- This [("abc",'X'),("def",'Y')] Just (Right ('A' :| "BCDE"))--- >>> Control.Lens.preview allTheseThoseB (This [("abc", 'x'), ("def", 'y')] Nothing)--- Just 'x'--- >>> Control.Lens.preview allTheseThoseB (This [("abc", 'x'), ("def", 'y')] (Just (Left ("abc":|["def"]))))--- Just 'x'--- >>> Control.Lens.preview allTheseThoseB (This [("abc", 'x'), ("def", 'y')] (Just (Right ('a':|"bcde"))))--- Just 'x'-allTheseThoseB ::-  Traversable f =>-  Traversal-    (This f a b)-    (This f a b')-    b-    b'-allTheseThoseB f (This t r) =-  let th =-        case r of-          Nothing ->-            pure Nothing-          Just (Left as) ->-            pure (Just (Left as))-          Just (Right bs) ->-            Just . Right <$> traverse f bs-  in  This <$>-        traverse (\(a, b) -> (a ,) <$> f b) t <*> th--allTheseThoseB1 ::-  Traversable1 f =>-  Traversal1-    (This f a b)-    (This f a b')-    b-    b'-allTheseThoseB1 f (This t r) =-  let x = This <$> traverse1 (\(a, b) -> (a ,) <$> f b) t-  in  maybe-        ((\k -> k Nothing) <$> x)-        (either-          (\z -> (\k -> k (Just (Left z))) <$> x)-          ((\p -> (\k -> k . Just . Right) <$> x <.> p) . traverse1 f))-          r+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# OPTIONS_GHC -Wall #-}+-- Suppress inline-rule-shadowing warnings for fusion RULES.+-- The warnings are benign: our RULES use phase [2] to avoid conflicts,+-- and they work correctly in optimized code where fusion matters.+{-# OPTIONS_GHC -Wno-inline-rule-shadowing #-}++module Data.Alignment+  ( -- * Data type+    This (..),+    This',++    -- * Type classes+    GetThis (..),+    HasThis (..),+    ReviewThis (..),+    AsThis (..),+    Semialign (..),+    Align (..),+    Unalign (..),++    -- * Lenses+    these,+    those,+    thoseLeft,+    thoseRight,++    -- * Traversals+    traverseA,+    traverseB,+    traverseA1,+    traverseB1,++    -- * Folds+    foldA,+    foldB,+    foldA1,+    foldB1,++    -- * Isomorphisms+    unaligned,++    -- * Law-checking functions+    semialignNaturality,+    semialignSymmetry,+    semialignCoherence,+    semialignWithLaw,+    alignRightIdentity,+    alignLeftIdentity,+    alignEmpty,+    unalignRoundtrip,+    unalignNaturality,+  )+where++import Control.Applicative+  ( Applicative (pure, (<*>)),+    ZipList (ZipList, getZipList),+    (<$>),+    (<*),+  )+import Control.Category (Category (id, (.)))+import Control.DeepSeq (NFData (rnf))+import Control.Lens+  ( Fold,+    Fold1,+    Getter,+    Identity (Identity),+    Iso',+    Lens,+    Lens',+    Prism',+    Review,+    Traversal,+    Traversal',+    Traversal1,+    iso,+    lens,+    over,+    prism',+    review,+    unto,+    view,+    _Left,+    _Right,+  )+import Data.Bifoldable (Bifoldable (bifoldMap))+import Data.Bifunctor (Bifunctor (bimap), second)+import Data.Bifunctor.Swap (Swap (..))+import Data.Bitraversable (Bitraversable (..))+import Data.Bool (Bool (False, True), otherwise, (&&))+import Data.Either (Either (..), either)+import Data.Eq (Eq ((==)))+import Data.Foldable (Foldable (foldMap), traverse_)+import Data.Function (const, flip, ($))+import Data.Tuple (uncurry)+import Data.Functor (Functor (fmap), ($>), (<$))+import Data.Functor.Apply (Apply ((<.>)), (.>))+import Data.Functor.Classes+  ( Eq1 (..),+    Eq2 (..),+    Ord1 (..),+    Ord2 (..),+    Show1 (..),+    Show2 (..),+    liftShowList2,+  )+import Data.Functor.Const (Const (Const))+import Data.IntMap (IntMap)+import qualified Data.IntMap as IntMap+import Data.List ((++))+import qualified Data.List as List+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NonEmpty (cons)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Maybe (Maybe (..))+import Data.Monoid (Monoid (mempty), (<>))+import Data.Ord (Ord (compare, min), (>))+import Data.Semigroup (Semigroup)+import Data.Semigroup.Bifoldable (Bifoldable1 (bifoldMap1))+import Data.Semigroup.Bitraversable (Bitraversable1 (bitraverse1))+import Data.Semigroup.Foldable (Foldable1 (foldMap1))+import Data.Semigroup.Traversable (Traversable1 (traverse1))+import Data.Sequence (Seq)+import qualified Data.Sequence as Seq+import Data.Traversable (Traversable (traverse))+import Data.Vector (Vector)+import qualified Data.Vector as Vector+import GHC.Generics (Generic, Generic1)+import GHC.Show (Show (showsPrec))+import Text.Show (showList, showParen, showString)++-- $setup+-- >>> import Prelude+-- >>> import Data.List.NonEmpty (NonEmpty(..))+-- >>> import qualified Data.Sequence as Seq+-- >>> import qualified Data.Vector as Vector+-- >>> import qualified Data.Map as Map+-- >>> import qualified Data.IntMap as IntMap+-- >>> import Data.Functor.Const (Const(..))++-- | Alignment result type combining matched pairs with leftovers+--+-- >>> This [(1,2)] Nothing :: This [] NonEmpty Int Int+-- This [(1,2)] Nothing+--+-- >>> This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int+-- This [(1,2)] (Just (Left (3 :| [])))+data This f g a b+  = This+      (f (a, b))+      (Maybe (Either (g a) (g b)))+  deriving (Generic, Generic1)++-- | Type alias for This when both functor parameters are the same+--+-- This simplifies the type signature when aligning structures where+-- leftovers on either side use the same container type.+--+-- >>> align (1 :| [2]) (3 :| [4,5]) :: This' NonEmpty Int Int+-- This ((1,3) :| [(2,4)]) (Just (Right (5 :| [])))+-- >>> align (Identity 1) (Identity 2) :: This' Identity Int Int+-- This (Identity (1,2)) Nothing+type This' f a b = This f f a b++-- | GetThis type class - provides a Getter to view a value as This+--+-- >>> import Control.Lens (view)+-- >>> view getThis (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- This [(1,2)] Nothing+class GetThis s f g a b | s -> f g a b where+  getThis ::+    Getter s (This f g a b)++instance GetThis (This f g a b) f g a b where+  getThis =+    id+  {-# INLINE getThis #-}++-- | HasThis type class - provides a Lens for This+--+-- >>> import Control.Lens (set)+-- >>> set this' (This [(3,4)] Nothing) (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- This [(3,4)] Nothing+class (GetThis s f g a b) => HasThis s f g a b | s -> f g a b where+  {-# MINIMAL setThis #-}+  setThis ::+    This f g a b -> s -> s+  this' ::+    Lens' s (This f g a b)+  this' =+    lens (view getThis) (flip setThis)+  {-# INLINE this' #-}++instance HasThis (This f g a b) f g a b where+  setThis =+    const+  {-# INLINE setThis #-}++-- | ReviewThis type class - provides a Review to construct a value from This+--+-- >>> review reviewThis (This [(1,2)] Nothing) :: This [] NonEmpty Int Int+-- This [(1,2)] Nothing+class ReviewThis s f g a b | s -> f g a b where+  reviewThis ::+    Review s (This f g a b)++instance ReviewThis (This f g a b) f g a b where+  reviewThis =+    unto id+  {-# INLINE reviewThis #-}++-- | AsThis type class - provides a Prism for This+--+-- >>> matchThis (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- Just (This [(1,2)] Nothing)+-- >>> import Control.Lens (preview)+-- >>> preview _This (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- Just (This [(1,2)] Nothing)+class (ReviewThis s f g a b) => AsThis s f g a b | s -> f g a b where+  {-# MINIMAL matchThis #-}+  matchThis ::+    s -> Maybe (This f g a b)+  _This ::+    Prism' s (This f g a b)+  _This =+    prism' (review reviewThis) matchThis+  {-# INLINE _This #-}++instance AsThis (This f g a b) f g a b where+  matchThis =+    Just+  {-# INLINE matchThis #-}++-- | Eq instance for This when all type parameters are concrete types with Eq+--+-- >>> (This [(1,2)] Nothing :: This [] NonEmpty Int Int) == This [(1,2)] Nothing+-- True+-- >>> (This [(1,2)] Nothing :: This [] NonEmpty Int Int) == This [(1,3)] Nothing+-- False+-- >>> (This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int) == This [(1,2)] (Just (Left (3 :| [])))+-- True+instance (Eq1 f, Eq1 g, Eq a, Eq b) => Eq (This f g a b) where+  This t1 r1 == This t2 r2 =+    liftEq (==) t1 t2 && liftEq (liftEq2 (liftEq (==)) (liftEq (==))) r1 r2++-- | Eq1 instance - makes the last type parameter (b) polymorphic+--+-- >>> liftEq (==) (This [(1,2)] Nothing) (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- True+-- >>> liftEq (==) (This [(1,2)] Nothing) (This [(1,3)] Nothing :: This [] NonEmpty Int Int)+-- False+instance (Eq1 f, Eq1 g, Eq a) => Eq1 (This f g a) where+  liftEq eqB (This t1 r1) (This t2 r2) =+    liftEq (liftEq2 (==) eqB) t1 t2 && liftEq (liftEq2 (liftEq (==)) (liftEq eqB)) r1 r2++-- | Eq2 instance - makes both type parameters (a, b) polymorphic+--+-- >>> liftEq2 (==) (==) (This [(1,2)] Nothing) (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- True+-- >>> liftEq2 (==) (==) (This [(1,2)] Nothing) (This [(2,2)] Nothing :: This [] NonEmpty Int Int)+-- False+instance (Eq1 f, Eq1 g) => Eq2 (This f g) where+  liftEq2 eqA eqB (This t1 r1) (This t2 r2) =+    liftEq (liftEq2 eqA eqB) t1 t2 && liftEq (liftEq2 (liftEq eqA) (liftEq eqB)) r1 r2++-- | Ord instance for This when all type parameters are concrete types with Ord+--+-- >>> compare (This [(1,2)] Nothing) (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- EQ+-- >>> compare (This [(1,2)] Nothing) (This [(1,3)] Nothing :: This [] NonEmpty Int Int)+-- LT+-- >>> compare (This [(2,2)] Nothing) (This [(1,3)] Nothing :: This [] NonEmpty Int Int)+-- GT+instance (Ord1 f, Ord1 g, Ord a, Ord b) => Ord (This f g a b) where+  compare (This t1 r1) (This t2 r2) =+    liftCompare compare t1 t2 <> liftCompare (liftCompare2 (liftCompare compare) (liftCompare compare)) r1 r2++-- | Ord1 instance - makes the last type parameter (b) polymorphic+--+-- >>> liftCompare compare (This [(1,2)] Nothing) (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- EQ+-- >>> liftCompare compare (This [(1,2)] Nothing) (This [(1,3)] Nothing :: This [] NonEmpty Int Int)+-- LT+instance (Ord1 f, Ord1 g, Ord a) => Ord1 (This f g a) where+  liftCompare cmpB (This t1 r1) (This t2 r2) =+    liftCompare (liftCompare2 compare cmpB) t1 t2 <> liftCompare (liftCompare2 (liftCompare compare) (liftCompare cmpB)) r1 r2++-- | Ord2 instance - makes both type parameters (a, b) polymorphic+--+-- >>> liftCompare2 compare compare (This [(1,2)] Nothing) (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- EQ+-- >>> liftCompare2 compare compare (This [(1,2)] Nothing) (This [(2,2)] Nothing :: This [] NonEmpty Int Int)+-- LT+instance (Ord1 f, Ord1 g) => Ord2 (This f g) where+  liftCompare2 cmpA cmpB (This t1 r1) (This t2 r2) =+    liftCompare (liftCompare2 cmpA cmpB) t1 t2 <> liftCompare (liftCompare2 (liftCompare cmpA) (liftCompare cmpB)) r1 r2++-- | Show instance for This when all type parameters are concrete types with Show+--+-- >>> This [(1,2)] Nothing :: This [] NonEmpty Int Int+-- This [(1,2)] Nothing+-- >>> This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int+-- This [(1,2)] (Just (Left (3 :| [])))+instance (Show1 f, Show1 g, Show a, Show b) => Show (This f g a b) where+  showsPrec d (This t r) =+    showParen (d > 10) $+      showString "This "+        . showsPrec 11 t+        . showString " "+        . showsPrec 11 r++-- | Show1 instance - makes the last type parameter (b) polymorphic+instance (Show1 f, Show1 g, Show a) => Show1 (This f g a) where+  liftShowsPrec spB slB d (This t r) =+    showParen (d > 10) $+      showString "This "+        . liftShowsPrec (liftShowsPrec2 showsPrec showList spB slB) (liftShowList2 showsPrec showList spB slB) 11 t+        . showString " "+        . liftShowsPrec (liftShowsPrec2 (liftShowsPrec showsPrec showList) (liftShowList showsPrec showList) (liftShowsPrec spB slB) (liftShowList spB slB)) (liftShowList2 (liftShowsPrec showsPrec showList) (liftShowList showsPrec showList) (liftShowsPrec spB slB) (liftShowList spB slB)) 11 r++-- | Show2 instance - makes both type parameters (a, b) polymorphic+instance (Show1 f, Show1 g) => Show2 (This f g) where+  liftShowsPrec2 spA slA spB slB d (This t r) =+    showParen (d > 10) $+      showString "This "+        . liftShowsPrec (liftShowsPrec2 spA slA spB slB) (liftShowList2 spA slA spB slB) 11 t+        . showString " "+        . liftShowsPrec (liftShowsPrec2 (liftShowsPrec spA slA) (liftShowList spA slA) (liftShowsPrec spB slB) (liftShowList spB slB)) (liftShowList2 (liftShowsPrec spA slA) (liftShowList spA slA) (liftShowsPrec spB slB) (liftShowList spB slB)) 11 r++-- | Functor instance - maps over the second type parameter (b)+-- Maps the function over b in the tuple (a,b) and over b in the Either branch+--+-- >>> fmap (*10) (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- This [(1,20)] Nothing+-- >>> fmap (*10) (This [(1,2)] (Just (Right (3 :| []))) :: This [] NonEmpty Int Int)+-- This [(1,20)] (Just (Right (30 :| [])))+-- >>> fmap (*10) (This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int)+-- This [(1,20)] (Just (Left (3 :| [])))+instance (Functor f, Functor g) => Functor (This f g a) where+  fmap h (This t r) =+    This (fmap (second h) t) (fmap (fmap (fmap h)) r)++-- | Bifunctor instance - operates on both type parameters (a, b)+-- The first function maps a, the second function maps b+--+-- >>> bimap (*10) (*100) (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- This [(10,200)] Nothing+-- >>> bimap (*10) (*100) (This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int)+-- This [(10,200)] (Just (Left (30 :| [])))+-- >>> bimap (*10) (*100) (This [(1,2)] (Just (Right (3 :| []))) :: This [] NonEmpty Int Int)+-- This [(10,200)] (Just (Right (300 :| [])))+instance (Functor f, Functor g) => Bifunctor (This f g) where+  bimap fa fb (This t r) =+    This (fmap (bimap fa fb) t) (fmap (bimap (fmap fa) (fmap fb)) r)++-- | Swap instance - swaps the two type parameters+--+-- >>> swap (This [(1,'a')] Nothing :: This [] NonEmpty Int Char)+-- This [('a',1)] Nothing+-- >>> swap (This [(1,'a')] (Just (Left (3 :| []))) :: This [] NonEmpty Int Char)+-- This [('a',1)] (Just (Right (3 :| [])))+-- >>> swap (This [(1,'a')] (Just (Right ('b' :| ""))) :: This [] NonEmpty Int Char)+-- This [('a',1)] (Just (Left ('b' :| "")))+instance (Functor f) => Swap (This f g) where+  swap (This t r) =+    This (fmap (\(a, b) -> (b, a)) t) (fmap swapEither r)+    where+      swapEither (Left ga) = Right ga+      swapEither (Right gb) = Left gb++-- | NFData instance for strict evaluation in benchmarks+--+-- Forces evaluation of both the paired component and the leftover component.+instance (NFData (f (a, b)), NFData (g a), NFData (g b)) => NFData (This f g a b) where+  rnf (This pairs leftover) = rnf (pairs, leftover)+  {-# INLINE rnf #-}++-- * Functor/Bifunctor/Swap fusion rules+--+-- These rules optimize composition of mapping and swapping operations on This.+-- Phase [2] ensures they fire after instance resolution.++{-# RULES++-- Functor composition on This - reduces to single traversal+"fmap/fmap/This" [2] forall f g (x :: This [] NonEmpty a b).+  fmap f (fmap g x) = fmap (f . g) x++-- Bifunctor composition on This - reduces to single traversal+"bimap/bimap/This" [2] forall f1 f2 g1 g2 (x :: This [] NonEmpty a b).+  bimap f1 g1 (bimap f2 g2 x) = bimap (f1 . f2) (g1 . g2) x++-- Swap involution - swap is its own inverse, complete elimination+"swap/swap/This" [2] forall (x :: This [] NonEmpty a b).+  swap (swap x) = x++-- Swap and bimap commute by swapping function arguments+"swap/bimap/This" [2] forall f g (x :: This [] NonEmpty a b).+  swap (bimap f g x) = bimap g f (swap x)++-- bimap and swap commute (reverse direction)+"bimap/swap/This" [2] forall f g (x :: This [] NonEmpty a b).+  bimap f g (swap x) = swap (bimap g f x)++  #-}++-- | Semigroup instance - combines two This values by combining their components+--+-- >>> This [(1,2)] Nothing <> This [(3,4)] Nothing :: This [] NonEmpty Int Int+-- This [(1,2),(3,4)] Nothing+-- >>> This [(1,2)] (Just (Left (3 :| []))) <> This [(4,5)] (Just (Left (6 :| [])))+-- This [(1,2),(4,5)] (Just (Left (3 :| [6])))+-- >>> This [(1,2)] (Just (Right (3 :| []))) <> This [(4,5)] (Just (Right (6 :| [])))+-- This [(1,2),(4,5)] (Just (Right (3 :| [6])))+-- >>> This [(1,2)] (Just (Left (3 :| []))) <> This [(4,5)] (Just (Right (6 :| [])))+-- This [(1,2),(4,5)] (Just (Right (6 :| [])))+instance (Semigroup (f (a, b)), Semigroup (g a), Semigroup (g b)) => Semigroup (This f g a b) where+  This t1 r1 <> This t2 r2 =+    This (t1 <> t2) (combine r1 r2)+    where+      combine Nothing Nothing = Nothing+      combine (Just x) Nothing = Just x+      combine Nothing (Just y) = Just y+      combine (Just (Left ga1)) (Just (Left ga2)) = Just (Left (ga1 <> ga2))+      combine (Just (Right gb1)) (Just (Right gb2)) = Just (Right (gb1 <> gb2))+      combine (Just (Left _)) (Just (Right gb)) = Just (Right gb)+      combine (Just (Right gb)) (Just (Left _)) = Just (Right gb)++-- | Monoid instance - identity is empty f and Nothing+--+-- >>> mempty :: This [] NonEmpty Int Int+-- This [] Nothing+-- >>> mempty <> This [(1,2)] Nothing :: This [] NonEmpty Int Int+-- This [(1,2)] Nothing+instance (Monoid (f (a, b)), Semigroup (g a), Semigroup (g b)) => Monoid (This f g a b) where+  mempty = This mempty Nothing++-- | Bifoldable instance - folds over both type parameters+--+-- >>> import Data.Monoid (Sum(..))+-- >>> bifoldMap Sum Sum (This [(1,2),(3,4)] Nothing :: This [] NonEmpty Int Int)+-- Sum {getSum = 10}+-- >>> bifoldMap Sum Sum (This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int)+-- Sum {getSum = 6}+-- >>> bifoldMap Sum Sum (This [(1,2)] (Just (Right (3 :| []))) :: This [] NonEmpty Int Int)+-- Sum {getSum = 6}+instance (Foldable f, Foldable g) => Bifoldable (This f g) where+  bifoldMap ha hb (This t r) =+    foldMap (\(a, b) -> ha a <> hb b) t <> foldMap (either (foldMap ha) (foldMap hb)) r+  {-# INLINE bifoldMap #-}++-- | Foldable instance - folds over b values in tuples and in the Either branch+--+-- >>> import Data.Monoid (Sum(..))+-- >>> foldMap Sum (This [(1,2),(3,4)] Nothing :: This [] NonEmpty Int Int)+-- Sum {getSum = 6}+-- >>> foldMap Sum (This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int)+-- Sum {getSum = 2}+-- >>> foldMap Sum (This [(1,2)] (Just (Right (3 :| []))) :: This [] NonEmpty Int Int)+-- Sum {getSum = 5}+instance (Foldable f, Foldable g) => Foldable (This f g a) where+  foldMap h (This t r) =+    foldMap (\(_, b) -> h b) t <> foldMap (either (pure mempty) (foldMap h)) r+  {-# INLINE foldMap #-}++-- | Bifoldable1 instance - folds over both type parameters with at least one value+--+-- >>> import Data.Semigroup (Sum(..))+-- >>> bifoldMap1 Sum Sum (This ((1,2) :| [(3,4)]) Nothing :: This NonEmpty NonEmpty Int Int)+-- Sum {getSum = 10}+-- >>> bifoldMap1 Sum Sum (This ((1,2) :| []) (Just (Left (3 :| []))) :: This NonEmpty NonEmpty Int Int)+-- Sum {getSum = 6}+-- >>> bifoldMap1 Sum Sum (This ((1,2) :| []) (Just (Right (3 :| []))) :: This NonEmpty NonEmpty Int Int)+-- Sum {getSum = 6}+instance (Foldable1 f, Foldable1 g) => Bifoldable1 (This f g) where+  bifoldMap1 ha hb (This t r) =+    case r of+      Nothing -> foldMap1 (\(a, b) -> ha a <> hb b) t+      Just (Left ga) -> foldMap1 (\(a, b) -> ha a <> hb b) t <> foldMap1 ha ga+      Just (Right gb) -> foldMap1 (\(a, b) -> ha a <> hb b) t <> foldMap1 hb gb+  {-# INLINE bifoldMap1 #-}++-- | Foldable1 instance - folds over at least one b value+--+-- >>> import Data.Semigroup (Sum(..))+-- >>> foldMap1 Sum (This ((1,2) :| [(3,4)]) Nothing :: This NonEmpty NonEmpty Int Int)+-- Sum {getSum = 6}+-- >>> foldMap1 Sum (This ((1,2) :| []) (Just (Left (3 :| []))) :: This NonEmpty NonEmpty Int Int)+-- Sum {getSum = 2}+-- >>> foldMap1 Sum (This ((1,2) :| []) (Just (Right (3 :| []))) :: This NonEmpty NonEmpty Int Int)+-- Sum {getSum = 5}+instance (Foldable1 f, Foldable1 g) => Foldable1 (This f g a) where+  foldMap1 h (This t r) =+    case r of+      Nothing -> foldMap1 (\(_, b) -> h b) t+      Just (Left _) -> foldMap1 (\(_, b) -> h b) t+      Just (Right gb) -> foldMap1 (\(_, b) -> h b) t <> foldMap1 h gb+  {-# INLINE foldMap1 #-}++-- | Traversable instance - traverses over b values+-- Implemented using traverseB+instance (Traversable f, Traversable g) => Traversable (This f g a) where+  traverse = traverseB++-- | Traversable1 instance - traverses over at least one b value+-- Implemented using traverseB1+instance (Traversable1 f, Traversable1 g) => Traversable1 (This f g a) where+  traverse1 = traverseB1++-- | Bitraversable instance - traverses over both type parameters+-- Implemented using traverseA and traverseB+--+-- >>> bitraverse Just Just (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- Just (This [(1,2)] Nothing)+-- >>> bitraverse (\x -> if x > 0 then Just x else Nothing) Just (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- Just (This [(1,2)] Nothing)+-- >>> bitraverse (\x -> if x > 0 then Just x else Nothing) Just (This [(-1,2)] Nothing :: This [] NonEmpty Int Int)+-- Nothing+instance (Traversable f, Traversable g) => Bitraversable (This f g) where+  bitraverse ha hb (This t r) =+    This+      <$> traverse (\(a, b) -> (,) <$> ha a <*> hb b) t+      <*> traverse traverseEither r+    where+      traverseEither (Left ga) = Left <$> traverse ha ga+      traverseEither (Right gb) = Right <$> traverse hb gb+  {-# INLINE bitraverse #-}++-- | Bitraversable1 instance - traverses over both type parameters with at least one value+-- Implemented using traverseA and traverseB with Apply+--+-- >>> bitraverse1 (Just) (Just) (This ((1,2) :| []) Nothing :: This NonEmpty NonEmpty Int Int)+-- Just (This ((1,2) :| []) Nothing)+instance (Traversable1 f, Traversable1 g) => Bitraversable1 (This f g) where+  bitraverse1 ha hb (This t r) =+    let tResult = traverse1 (\(a, b) -> (,) <$> ha a <.> hb b) t+     in case r of+          Nothing -> (`This` Nothing) <$> tResult+          Just (Left ga) -> (\t' ga' -> This t' (Just (Left ga'))) <$> tResult <.> traverse1 ha ga+          Just (Right gb) -> (\t' gb' -> This t' (Just (Right gb'))) <$> tResult <.> traverse1 hb gb+  {-# INLINE bitraverse1 #-}++-- | Semialign type class - aligns two functors into a This value+--+-- >>> align [1,2,3] [4,5] :: This [] NonEmpty Int Int+-- This [(1,4),(2,5)] (Just (Left (3 :| [])))+-- >>> align [1,2] [3,4,5] :: This [] NonEmpty Int Int+-- This [(1,3),(2,4)] (Just (Right (5 :| [])))+-- >>> align [1,2] [3,4] :: This [] NonEmpty Int Int+-- This [(1,3),(2,4)] Nothing+--+-- = Laws+--+-- [Naturality (Bifunctoriality)]+--+--   Mapping over the aligned result is the same as mapping over the inputs first:+--+--   @bimap f g (align xs ys) ≡ align (fmap f xs) (fmap g ys)@+--+-- [Symmetry]+--+--   Aligning x with y should be the same as aligning y with x and swapping:+--+--   @align x y ≡ swap (align y x)@+--+-- [Coherence with alignWith]+--+--   The relationship between 'align' and 'alignWith' must be consistent:+--+--   @align x y ≡ alignWith id id id x y@+--+--   @alignWith f g h x y ≡+--     let This t r = align x y+--     in This (fmap f t) (fmap (bimap (fmap g) (fmap h)) r)@+--+-- [Preservation of structure]+--+--   No elements should be duplicated or lost. The total number of elements+--   in matched pairs plus elements in leftovers equals the total input elements.+--+-- See 'semialignNaturality', 'semialignSymmetry', 'semialignCoherence' for+-- testable property functions.+class (Functor f, Functor g) => Semialign f g | f -> g where+  align ::+    f a ->+    f b ->+    This f g a b+  align =+    alignWith id id id++  -- | Align with a transformation function+  --+  -- >>> alignWith (\(a,b) -> (a*10, b*100)) (*10) (*100) [1,2,3] [4,5] :: This [] NonEmpty Int Int+  -- This [(10,400),(20,500)] (Just (Left (30 :| [])))+  alignWith ::+    ((a, b) -> (c, d)) ->+    (a -> c) ->+    (b -> d) ->+    f a ->+    f b ->+    This f g c d+  alignWith f g h t1 t2 =+    case align t1 t2 of+      This t r ->+        This (fmap f t) (fmap (bimap (fmap g) (fmap h)) r)++  {-# MINIMAL align | alignWith #-}++  -- | Simplified alignWith using bimap+  --+  -- >>> alignWith' (*10) (*100) [1,2,3] [4,5] :: This [] NonEmpty Int Int+  -- This [(10,400),(20,500)] (Just (Left (30 :| [])))+  alignWith' ::+    (a -> c) ->+    (b -> d) ->+    f a ->+    f b ->+    This f g c d+  alignWith' f g =+    alignWith (bimap f g) f g+  {-# INLINE alignWith' #-}++-- * Fusion rules+--+-- These RULES enable GHC to fuse operations for better performance,+-- eliminating intermediate This allocations where possible.+--+-- Phase [2] ensures these fire after class method specialization,+-- allowing them to see concrete instances while avoiding conflicts+-- with earlier optimization phases.++{-# RULES++-- Naturality fusion: fuse bimap into align+-- Implements the semialignNaturality law as a rewrite rule+"semialign/naturality" [2] forall f g xs ys.+  bimap f g (align xs ys) = alignWith (bimap f g) f g xs ys++-- Composition fusion for alignWith followed by bimap+"alignWith/bimap" [2] forall w x y k l xs ys.+  bimap k l (alignWith w x y xs ys) =+    alignWith (bimap k l . w) (k . x) (l . y) xs ys++-- Symmetry via swap: align x y = swap (align y x)+-- Can enable other optimizations when combined with swap rules+"align/swap/symmetry" [2] forall x y.+  swap (align y x) = align x y++-- fmap can be expressed as bimap with identity on first param+-- Allows bimap rules to catch fmap patterns+"fmap/as/bimap" [2] forall f (x :: This [] NonEmpty a b).+  fmap f x = bimap id f x++  #-}++-- | Semialign instance for Identity - always produces a perfect match+--+-- >>> align (Identity 1) (Identity 2)+-- This (Identity (1,2)) Nothing+instance Semialign Identity Identity where+  align (Identity a) (Identity b) =+    This (Identity (a, b)) Nothing+  {-# INLINE align #-}++-- | Semialign instance for lists - aligns elements pairwise+--+-- >>> align [1,2,3] [4,5] :: This [] NonEmpty Int Int+-- This [(1,4),(2,5)] (Just (Left (3 :| [])))+-- >>> align [1,2] [3,4,5] :: This [] NonEmpty Int Int+-- This [(1,3),(2,4)] (Just (Right (5 :| [])))+-- >>> align [1,2] [3,4] :: This [] NonEmpty Int Int+-- This [(1,3),(2,4)] Nothing+-- >>> align ([] :: [Int]) [1,2] :: This [] NonEmpty Int Int+-- This [] (Just (Right (1 :| [2])))+instance Semialign [] NonEmpty where+  align (a : as) (b : bs) =+    let This t r = align as bs+     in This ((a, b) : t) r+  align (a : as) [] =+    This [] (Just (Left (a :| as)))+  align [] (b : bs) =+    This [] (Just (Right (b :| bs)))+  align [] [] =+    This [] Nothing+  {-# INLINABLE align #-}++-- | Semialign instance for Maybe - aligns optional values+--+-- >>> align (Just 1) (Just 2) :: This Maybe Identity Int Int+-- This (Just (1,2)) Nothing+-- >>> align (Just 1) Nothing :: This Maybe Identity Int Int+-- This Nothing (Just (Left (Identity 1)))+-- >>> align Nothing (Just 2) :: This Maybe Identity Int Int+-- This Nothing (Just (Right (Identity 2)))+-- >>> align Nothing Nothing :: This Maybe Identity Int Int+-- This Nothing Nothing+instance Semialign Maybe Identity where+  align (Just a) (Just b) =+    This (Just (a, b)) Nothing+  align (Just a) Nothing =+    This Nothing (Just (Left (Identity a)))+  align Nothing (Just b) =+    This Nothing (Just (Right (Identity b)))+  align Nothing Nothing =+    This Nothing Nothing+  {-# INLINABLE align #-}++-- | Semialign instance for NonEmpty - aligns non-empty lists+--+-- >>> align (1 :| [2,3]) (4 :| [5])+-- This ((1,4) :| [(2,5)]) (Just (Left (3 :| [])))+-- >>> align (1 :| [2]) (3 :| [4,5])+-- This ((1,3) :| [(2,4)]) (Just (Right (5 :| [])))+-- >>> align (1 :| [2]) (3 :| [4])+-- This ((1,3) :| [(2,4)]) Nothing+-- >>> align (1 :| []) (2 :| [])+-- This ((1,2) :| []) Nothing+instance Semialign NonEmpty NonEmpty where+  align (h1 :| []) (h2 :| []) =+    This ((h1, h2) :| []) Nothing+  align (h1 :| i1 : r1) (h2 :| []) =+    This ((h1, h2) :| []) (Just (Left (i1 :| r1)))+  align (h1 :| []) (h2 :| i2 : r2) =+    This ((h1, h2) :| []) (Just (Right (i2 :| r2)))+  align (h1 :| i1 : r1) (h2 :| i2 : r2) =+    let This t r = align (i1 :| r1) (i2 :| r2)+     in This ((h1, h2) `NonEmpty.cons` t) r+  {-# INLINABLE align #-}++-- | Semialign instance for ZipList - delegates to list alignment+--+-- >>> import Control.Lens (view)+-- >>> view these (align (ZipList [1,2,3]) (ZipList [4,5]))+-- ZipList {getZipList = [(1,4),(2,5)]}+instance Semialign ZipList NonEmpty where+  align (ZipList a) (ZipList b) =+    over these ZipList (align a b)+  {-# INLINABLE align #-}++-- | Semialign instance for Seq - aligns sequences element-wise+--+-- >>> align (Seq.fromList [1,2,3]) (Seq.fromList [4,5]) :: This Seq NonEmpty Int Int+-- This (fromList [(1,4),(2,5)]) (Just (Left (3 :| [])))+-- >>> align (Seq.fromList [1,2]) (Seq.fromList [3,4,5]) :: This Seq NonEmpty Int Int+-- This (fromList [(1,3),(2,4)]) (Just (Right (5 :| [])))+-- >>> align (Seq.fromList [1,2]) (Seq.fromList [3,4]) :: This Seq NonEmpty Int Int+-- This (fromList [(1,3),(2,4)]) Nothing+instance Semialign Seq NonEmpty where+  align sa sb = case (Seq.viewl sa, Seq.viewl sb) of+    (Seq.EmptyL, Seq.EmptyL) -> This Seq.empty Nothing+    (a Seq.:< as, Seq.EmptyL) -> This Seq.empty (Just (Left (a :| toList as)))+    (Seq.EmptyL, b Seq.:< bs) -> This Seq.empty (Just (Right (b :| toList bs)))+    (a Seq.:< as, b Seq.:< bs) ->+      let This t r = align as bs+       in This ((a, b) Seq.<| t) r+    where+      toList s = case Seq.viewl s of+        Seq.EmptyL -> []+        x Seq.:< xs -> x : toList xs+  {-# INLINABLE align #-}++-- | Semialign instance for Vector - aligns vectors element-wise+--+-- >>> align (Vector.fromList [1,2,3]) (Vector.fromList [4,5]) :: This Vector NonEmpty Int Int+-- This [(1,4),(2,5)] (Just (Left (3 :| [])))+-- >>> align (Vector.fromList [1,2]) (Vector.fromList [3,4,5]) :: This Vector NonEmpty Int Int+-- This [(1,3),(2,4)] (Just (Right (5 :| [])))+instance Semialign Vector NonEmpty where+  align va vb =+    let minLen = min (Vector.length va) (Vector.length vb)+        paired = Vector.zip (Vector.take minLen va) (Vector.take minLen vb)+        leftover+          | Vector.length va > minLen =+              case Vector.toList (Vector.drop minLen va) of+                [] -> Nothing+                (x : xs) -> Just (Left (x :| xs))+          | Vector.length vb > minLen =+              case Vector.toList (Vector.drop minLen vb) of+                [] -> Nothing+                (y : ys) -> Just (Right (y :| ys))+          | otherwise = Nothing+     in This paired leftover+  {-# INLINABLE align #-}++-- | Semialign instance for Map - aligns by keys+--+-- >>> let m1 = Map.fromList [(1,'a'),(2,'b'),(3,'c')]+-- >>> let m2 = Map.fromList [(2,'x'),(3,'y'),(4,'z')]+-- >>> align m1 m2 :: This (Map Int) (Map Int) Char Char+-- This (fromList [(2,('b','x')),(3,('c','y'))]) (Just (Left (fromList [(1,'a')])))+instance (Ord k) => Semialign (Map k) (Map k) where+  align m1 m2 =+    let both = Map.intersectionWith (,) m1 m2+        onlyLeft = Map.difference m1 m2+        onlyRight = Map.difference m2 m1+        leftover = case (Map.null onlyLeft, Map.null onlyRight) of+          (True, True) -> Nothing+          (False, True) -> Just (Left onlyLeft)+          (True, False) -> Just (Right onlyRight)+          (False, False) -> Just (Left onlyLeft) -- Left takes precedence+     in This both leftover+  {-# INLINABLE align #-}++-- | Semialign instance for IntMap - aligns by Int keys+--+-- >>> let m1 = IntMap.fromList [(1,'a'),(2,'b'),(3,'c')]+-- >>> let m2 = IntMap.fromList [(2,'x'),(3,'y'),(4,'z')]+-- >>> align m1 m2 :: This IntMap IntMap Char Char+-- This (fromList [(2,('b','x')),(3,('c','y'))]) (Just (Left (fromList [(1,'a')])))+instance Semialign IntMap IntMap where+  align m1 m2 =+    let both = IntMap.intersectionWith (,) m1 m2+        onlyLeft = IntMap.difference m1 m2+        onlyRight = IntMap.difference m2 m1+        leftover = case (IntMap.null onlyLeft, IntMap.null onlyRight) of+          (True, True) -> Nothing+          (False, True) -> Just (Left onlyLeft)+          (True, False) -> Just (Right onlyRight)+          (False, False) -> Just (Left onlyLeft)+     in This both leftover+  {-# INLINABLE align #-}++-- | Semialign instance for functions - pointwise alignment+--+-- >>> let f = align (+1) (*2) :: This ((->) Int) Identity Int Int+-- >>> view these f 5+-- (6,10)+instance Semialign ((->) r) Identity where+  align f g = This (\r -> (f r, g r)) Nothing+  {-# INLINE align #-}++-- | Semialign instance for pairs with Monoid first component+--+-- >>> align (mempty :: String, 1) ("", 2) :: This ((,) String) Identity Int Int+-- This ("",(1,2)) Nothing+-- >>> align ("left", 1) ("right", 2) :: This ((,) String) Identity Int Int+-- This ("leftright",(1,2)) Nothing+instance (Monoid e) => Semialign ((,) e) Identity where+  align (e1, a) (e2, b) = This (e1 <> e2, (a, b)) Nothing+  {-# INLINE align #-}++-- | Semialign instance for Const - trivial alignment+--+-- >>> align (Const "left") (Const "right") :: This (Const String) Identity Int Int+-- This (Const "left") Nothing+instance Semialign (Const m) Identity where+  align (Const a) (Const _) = This (Const a) Nothing+  {-# INLINE align #-}++-- | Align type class - Semialign with an empty structure+--+-- This is to Semialign as Applicative is to Apply.+-- The relationship: Semialign : Apply :: Align : Applicative+--+-- The 'nil' method provides an empty structure, which acts as an identity+-- for alignment operations.+--+-- = Laws+--+-- In addition to the Semialign laws, Align instances must satisfy:+--+-- [Right identity]+--+--   Aligning with nil on the right produces only left leftovers:+--+--   @align x nil ≡ This nil (toLeftover x)@+--+-- [Left identity]+--+--   Aligning with nil on the left produces only right leftovers:+--+--   @align nil y ≡ This nil (toRightover y)@+--+-- [Empty alignment]+--+--   Aligning nil with nil produces an empty result:+--+--   @align nil nil ≡ This nil Nothing@+--+-- Where 'toLeftover' and 'toRightover' convert non-empty structures to the+-- leftover type 'g'. For empty inputs, these return 'Nothing'.+--+-- Not all Semialign instances can be Align instances. For example, NonEmpty+-- cannot be Align because there is no empty NonEmpty.+--+-- >>> align (nil :: [Int]) [1,2] :: This [] NonEmpty Int Int+-- This [] (Just (Right (1 :| [2])))+-- >>> align [1,2] (nil :: [Int]) :: This [] NonEmpty Int Int+-- This [] (Just (Left (1 :| [2])))+-- >>> align (nil :: Maybe Int) (Just 5) :: This Maybe Identity Int Int+-- This Nothing (Just (Right (Identity 5)))+--+-- See 'alignRightIdentity', 'alignLeftIdentity', 'alignEmpty' for+-- testable property functions.+class (Semialign f g) => Align f g where+  -- | The empty structure - identity for alignment+  nil :: f a++-- | Align instance for lists+--+-- >>> nil :: [Int]+-- []+-- >>> align nil [1,2,3] :: This [] NonEmpty Int Int+-- This [] (Just (Right (1 :| [2,3])))+instance Align [] NonEmpty where+  nil = []+  {-# INLINE nil #-}++-- | Align instance for Maybe+--+-- >>> nil :: Maybe Int+-- Nothing+-- >>> align nil (Just 42) :: This Maybe Identity Int Int+-- This Nothing (Just (Right (Identity 42)))+instance Align Maybe Identity where+  nil = Nothing+  {-# INLINE nil #-}++-- | Align instance for ZipList+--+-- >>> nil :: ZipList Int+-- ZipList {getZipList = []}+-- >>> import Control.Lens (view)+-- >>> view these (align nil (ZipList [1,2]))+-- ZipList {getZipList = []}+instance Align ZipList NonEmpty where+  nil = ZipList []+  {-# INLINE nil #-}++-- | Align instance for Seq+--+-- >>> nil :: Seq Int+-- fromList []+-- >>> align nil (Seq.fromList [1,2]) :: This Seq NonEmpty Int Int+-- This (fromList []) (Just (Right (1 :| [2])))+instance Align Seq NonEmpty where+  nil = Seq.empty+  {-# INLINE nil #-}++-- | Align instance for Vector+--+-- >>> nil :: Vector Int+-- []+-- >>> align nil (Vector.fromList [1,2]) :: This Vector NonEmpty Int Int+-- This [] (Just (Right (1 :| [2])))+instance Align Vector NonEmpty where+  nil = Vector.empty+  {-# INLINE nil #-}++-- | Align instance for Map+--+-- >>> nil :: Map Int Char+-- fromList []+-- >>> let m = Map.fromList [(1,'a'),(2,'b')]+-- >>> align nil m :: This (Map Int) (Map Int) Char Char+-- This (fromList []) (Just (Right (fromList [(1,'a'),(2,'b')])))+instance (Ord k) => Align (Map k) (Map k) where+  nil = Map.empty+  {-# INLINE nil #-}++-- | Align instance for IntMap+--+-- >>> nil :: IntMap Char+-- fromList []+-- >>> let m = IntMap.fromList [(1,'a'),(2,'b')]+-- >>> align nil m :: This IntMap IntMap Char Char+-- This (fromList []) (Just (Right (fromList [(1,'a'),(2,'b')])))+instance Align IntMap IntMap where+  nil = IntMap.empty+  {-# INLINE nil #-}++-- | Align instance for Const with Monoid+--+-- >>> nil :: Const String Int+-- Const ""+instance (Monoid m) => Align (Const m) Identity where+  nil = Const mempty+  {-# INLINE nil #-}++-- Note: Product and Compose instances would require more complex type machinery+-- and are omitted for simplicity. They could be added with careful handling of+-- the leftover types.++-- | Unalign type class - recover original functors from alignment+--+-- Not all Semialign instances can be Unalign. This class is for functors+-- where the alignment can be reversed without loss of information.+--+-- The Unalign class provides the inverse of 'align', allowing you to recover+-- the original two functors from a 'This' value. This is only possible for+-- container-like functors that support both unzipping and merging operations.+--+-- = Laws+--+-- [Roundtrip]+--+--   The fundamental law is that unalign inverts align:+--+--   @unalign (align xs ys) ≡ (xs, ys)@+--+-- [Naturality]+--+--   Unalign commutes with fmap on both sides:+--+--   @bimap (fmap f) (fmap g) (unalign t) ≡ unalign (bimap f g t)@+--+-- [Isomorphism]+--+--   The 'aligned' Iso satisfies the isomorphism laws:+--+--   @from aligned . to aligned ≡ id@+--   @to aligned . from aligned ≡ id@+--+--   Where @to aligned = uncurry align@ and @from aligned = unalign@.+--+-- = Important Notes+--+-- Not all Semialign instances can be Unalign instances:+--+-- * Sequence types ([], Maybe, NonEmpty, Vector, Seq, etc.) ✓ Can unalign+-- * Function types ((->) r) ✗ Cannot meaningfully merge functions with constants+-- * Pair types ((,) e) ✗ Would require duplicating the first component+-- * Map and IntMap ✗ Violate roundtrip law when both sides have leftovers+--+-- For Map and IntMap, when both sides have leftovers, 'align' keeps only left+-- leftovers (left takes precedence), so 'unalign' cannot recover the original+-- right-side keys. We choose not to provide these instances to keep the type+-- class lawful.+--+-- See 'unalignRoundtrip' and 'unalignNaturality' for testable property functions.+--+-- >>> unalign (align [1,2,3] [10,20] :: This [] NonEmpty Int Int)+-- ([1,2,3],[10,20])+-- >>> unalign (align (Just 1) Nothing :: This Maybe Identity Int Int)+-- (Just 1,Nothing)+class (Semialign f g) => Unalign f g where+  {-# MINIMAL unalign #-}++  -- | Recover the original functors from an aligned result+  unalign :: This f g a b -> (f a, f b)++  -- | Unalign with transformation - transforms both sides during unalignment+  --+  -- This is the dual of 'alignWith': while @alignWith@ transforms during alignment,+  -- @unalignWith@ transforms during unalignment.+  --+  -- >>> unalignWith (*10) (*100) (This [(1,2),(3,4)] Nothing :: This [] NonEmpty Int Int)+  -- ([10,30],[200,400])+  -- >>> unalignWith (*10) (*100) (This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int)+  -- ([10,30],[200])+  -- >>> unalignWith (*10) (*100) (This [(1,2)] (Just (Right (5 :| []))) :: This [] NonEmpty Int Int)+  -- ([10],[200,500])+  unalignWith ::+    (a -> c) ->+    (b -> d) ->+    This f g a b ->+    (f c, f d)+  unalignWith f g = unalign . bimap f g+  {-# INLINE unalignWith #-}++  -- | Isomorphism between a pair of functors and their alignment+  --+  -- This witnesses that @(f a, f b)@ and @This f g a b@ are isomorphic,+  -- meaning alignment is completely lossless for Unalign instances.+  --+  -- >>> import Control.Lens (from, view)+  -- >>> view aligned ([1,2,3], [10,20]) :: This [] NonEmpty Int Int+  -- This [(1,10),(2,20)] (Just (Left (3 :| [])))+  -- >>> view (from aligned) (This [(1,10),(2,20)] (Just (Left (3 :| [])))) :: ([Int], [Int])+  -- ([1,2,3],[10,20])+  aligned :: Iso' (f a, f b) (This f g a b)+  aligned = iso (uncurry align) unalign+  {-# INLINE aligned #-}++-- | Isomorphism between an aligned result and a pair of functors+--+-- This is the inverse of 'aligned', providing a direct view from+-- @This f g a b@ to @(f a, f b)@.+--+-- >>> import Control.Lens (view, from)+-- >>> view unaligned (This [(1,10),(2,20)] (Just (Left (3 :| [])))) :: ([Int], [Int])+-- ([1,2,3],[10,20])+-- >>> view (from unaligned) ([1,2,3], [10,20]) :: This [] NonEmpty Int Int+-- This [(1,10),(2,20)] (Just (Left (3 :| [])))+unaligned :: (Unalign f g) => Iso' (This f g a b) (f a, f b)+unaligned = iso unalign (uncurry align)+{-# INLINE unaligned #-}++-- * Unalign fusion rules+--+-- Additional fusion rules specific to Unalign instances.+--+-- Phase [2] ensures these fire after class method specialization.++{-# RULES++-- Roundtrip elimination: unalign immediately after align+-- Implements the unalignRoundtrip law as a rewrite rule+"unalign/align/roundtrip" [2] forall xs ys.+  unalign (align xs ys) = (xs, ys)++-- Naturality for unalign: push bimap through unalign+-- Implements the unalignNaturality law as a rewrite rule+"unalign/bimap/naturality" [2] forall f g this.+  bimap (fmap f) (fmap g) (unalign this) = unalign (bimap f g this)++-- unalignWith/align roundtrip with transformation+-- Combines roundtrip elimination with transformation fusion+"unalignWith/align" [2] forall f g xs ys.+  unalignWith f g (align xs ys) = (fmap f xs, fmap g ys)++  #-}++-- | Unalign instance for Identity - simply unwrap+--+-- >>> unalign (align (Identity 1) (Identity 2) :: This Identity Identity Int Int)+-- (Identity 1,Identity 2)+instance Unalign Identity Identity where+  unalign (This (Identity (a, b)) _) = (Identity a, Identity b)+  {-# INLINE unalign #-}++-- | Unalign instance for lists - unzip and append leftovers+--+-- >>> unalign (align [1,2,3] [10,20] :: This [] NonEmpty Int Int)+-- ([1,2,3],[10,20])+-- >>> unalign (align [1,2] [10,20,30] :: This [] NonEmpty Int Int)+-- ([1,2],[10,20,30])+-- >>> unalign (align [1,2] [10,20] :: This [] NonEmpty Int Int)+-- ([1,2],[10,20])+instance Unalign [] NonEmpty where+  unalign (This pairs mleftover) =+    let (as, bs) = List.unzip pairs+     in case mleftover of+          Nothing -> (as, bs)+          Just (Left ga) -> (as ++ toList ga, bs)+          Just (Right gb) -> (as, bs ++ toList gb)+    where+      toList (x :| xs) = x : xs+  {-# INLINABLE unalign #-}++-- | Unalign instance for Maybe - reconstruct from pairs or leftovers+--+-- >>> unalign (align (Just 1) (Just 2) :: This Maybe Identity Int Int)+-- (Just 1,Just 2)+-- >>> unalign (align (Just 1) Nothing :: This Maybe Identity Int Int)+-- (Just 1,Nothing)+-- >>> unalign (align Nothing (Just 2) :: This Maybe Identity Int Int)+-- (Nothing,Just 2)+-- >>> unalign (align Nothing Nothing :: This Maybe Identity Int Int)+-- (Nothing,Nothing)+instance Unalign Maybe Identity where+  unalign (This pairs mleftover) =+    case (pairs, mleftover) of+      (Nothing, Nothing) -> (Nothing, Nothing)+      (Just (a, b), Nothing) -> (Just a, Just b)+      (Nothing, Just (Left (Identity a))) -> (Just a, Nothing)+      (Nothing, Just (Right (Identity b))) -> (Nothing, Just b)+      -- The cases with both pairs and leftovers are impossible for Maybe+      _ -> (Nothing, Nothing)+  {-# INLINE unalign #-}++-- | Unalign instance for NonEmpty - unzip and append leftovers+--+-- >>> unalign (align (1 :| [2,3]) (10 :| [20]) :: This NonEmpty NonEmpty Int Int)+-- (1 :| [2,3],10 :| [20])+-- >>> unalign (align (1 :| [2]) (10 :| [20,30]) :: This NonEmpty NonEmpty Int Int)+-- (1 :| [2],10 :| [20,30])+-- >>> unalign (align (1 :| [2]) (10 :| [20]) :: This NonEmpty NonEmpty Int Int)+-- (1 :| [2],10 :| [20])+instance Unalign NonEmpty NonEmpty where+  unalign (This pairs mleftover) =+    let (leftAs, leftBs) = unzipNonEmpty pairs+     in case mleftover of+          Nothing -> (leftAs, leftBs)+          Just (Left ga) -> (leftAs <> ga, leftBs)+          Just (Right gb) -> (leftAs, leftBs <> gb)+    where+      unzipNonEmpty ((x, y) :| rest) =+        let (xs, ys) = List.unzip rest+         in (x :| xs, y :| ys)+  {-# INLINABLE unalign #-}++-- | Unalign instance for ZipList - delegates to list unalign+--+-- >>> unalign (align (ZipList [1,2,3]) (ZipList [10,20]) :: This ZipList NonEmpty Int Int)+-- (ZipList {getZipList = [1,2,3]},ZipList {getZipList = [10,20]})+instance Unalign ZipList NonEmpty where+  unalign t =+    let (as, bs) = unalign (over these getZipList t)+     in (ZipList as, ZipList bs)+  {-# INLINE unalign #-}++-- | Unalign instance for Seq - unzip and append leftovers+--+-- >>> unalign (align (Seq.fromList [1,2,3]) (Seq.fromList [10,20]) :: This Seq NonEmpty Int Int)+-- (fromList [1,2,3],fromList [10,20])+-- >>> unalign (align (Seq.fromList [1,2]) (Seq.fromList [10,20,30]) :: This Seq NonEmpty Int Int)+-- (fromList [1,2],fromList [10,20,30])+instance Unalign Seq NonEmpty where+  unalign (This pairs mleftover) =+    let (as, bs) = unzipSeq pairs+     in case mleftover of+          Nothing -> (as, bs)+          Just (Left ga) -> (as Seq.>< fromNonEmpty ga, bs)+          Just (Right gb) -> (as, bs Seq.>< fromNonEmpty gb)+    where+      unzipSeq s = case Seq.viewl s of+        Seq.EmptyL -> (Seq.empty, Seq.empty)+        (a, b) Seq.:< rest ->+          let (as, bs) = unzipSeq rest+           in (a Seq.<| as, b Seq.<| bs)+      fromNonEmpty (x :| xs) = x Seq.<| Seq.fromList xs+  {-# INLINE unalign #-}++-- | Unalign instance for Vector - unzip and append leftovers+--+-- >>> unalign (align (Vector.fromList [1,2,3]) (Vector.fromList [10,20]) :: This Vector NonEmpty Int Int)+-- ([1,2,3],[10,20])+-- >>> unalign (align (Vector.fromList [1,2]) (Vector.fromList [10,20,30]) :: This Vector NonEmpty Int Int)+-- ([1,2],[10,20,30])+instance Unalign Vector NonEmpty where+  unalign (This pairs mleftover) =+    let (as, bs) = Vector.unzip pairs+     in case mleftover of+          Nothing -> (as, bs)+          Just (Left ga) -> (as Vector.++ fromNonEmpty ga, bs)+          Just (Right gb) -> (as, bs Vector.++ fromNonEmpty gb)+    where+      fromNonEmpty (x :| xs) = Vector.cons x (Vector.fromList xs)+  {-# INLINABLE unalign #-}++-- Note: Map and IntMap do NOT have Unalign instances because their Semialign+-- instances violate the roundtrip law. When both sides have leftovers, align+-- keeps only left leftovers (left takes precedence), so unalign cannot recover+-- the original right-side keys. We prefer to have a lawful type class rather+-- than instances with caveats.++-- * Law-checking functions+--+-- These functions can be used in property-based tests to verify that+-- instances satisfy the required laws.++-- | Test the naturality law for Semialign+--+-- Property: @bimap f g (align xs ys) ≡ align (fmap f xs) (fmap g ys)@+--+-- >>> semialignNaturality (*10) (*100) [1,2,3] [4,5] :: Bool+-- True+-- >>> semialignNaturality (*10) (*100) [1,2] [3,4,5] :: Bool+-- True+semialignNaturality ::+  (Semialign f g, Eq1 f, Eq1 g, Eq c, Eq d) =>+  (a -> c) ->+  (b -> d) ->+  f a ->+  f b ->+  Bool+semialignNaturality f g xs ys =+  liftEq2 (==) (==) (bimap f g (align xs ys)) (align (fmap f xs) (fmap g ys))++-- | Test the symmetry law for Semialign+--+-- Property: @align x y ≡ swap (align y x)@+--+-- >>> semialignSymmetry [1,2,3] [4,5] :: Bool+-- True+-- >>> semialignSymmetry [1,2] [3,4,5] :: Bool+-- True+-- >>> semialignSymmetry (Just 1) (Just 2) :: Bool+-- True+semialignSymmetry ::+  (Semialign f g, Eq1 f, Eq1 g, Eq a, Eq b) =>+  f a ->+  f b ->+  Bool+semialignSymmetry x y =+  liftEq2 (==) (==) (align x y) (swap (align y x))++-- | Test the coherence law between align and alignWith+--+-- Property: @align x y ≡ alignWith id id id x y@+--+-- >>> semialignCoherence [1,2,3] [4,5] :: Bool+-- True+-- >>> semialignCoherence (Just 1) (Just 2) :: Bool+-- True+semialignCoherence ::+  (Semialign f g, Eq1 f, Eq1 g, Eq a, Eq b) =>+  f a ->+  f b ->+  Bool+semialignCoherence x y =+  liftEq2 (==) (==) (align x y) (alignWith id id id x y)++-- | Test the alignWith transformation law+--+-- Property: @alignWith f g h x y ≡ let This t r = align x y in This (fmap f t) (fmap (bimap (fmap g) (fmap h)) r)@+--+-- >>> semialignWithLaw (\(a,b) -> (a*10, b*100)) (*10) (*100) [1,2,3] [4,5] :: Bool+-- True+semialignWithLaw ::+  (Semialign f g, Eq1 f, Eq1 g, Eq c, Eq d) =>+  ((a, b) -> (c, d)) ->+  (a -> c) ->+  (b -> d) ->+  f a ->+  f b ->+  Bool+semialignWithLaw f g h x y =+  let result1 = alignWith f g h x y+      This t r = align x y+      result2 = This (fmap f t) (fmap (bimap (fmap g) (fmap h)) r)+   in liftEq2 (==) (==) result1 result2++-- | Test the right identity law for Align+--+-- Property: When aligning with nil on the right, paired part is empty+--+-- >>> alignRightIdentity [1,2,3] ([] :: [Char])+-- True+-- >>> alignRightIdentity (Just 42) (Nothing :: Maybe Char)+-- True+-- >>> alignRightIdentity ([] :: [Int]) ([] :: [Char])+-- True+alignRightIdentity ::+  (Align f g, Eq1 f, Eq a, Eq b) =>+  f a ->+  f b ->+  Bool+alignRightIdentity x emptyY =+  case align x emptyY of+    This t Nothing -> liftEq (==) t nil+    This t (Just (Left _)) -> liftEq (==) t nil+    _ -> False++-- | Test the left identity law for Align+--+-- Property: When aligning with nil on the left, paired part is empty+--+-- >>> alignLeftIdentity ([] :: [Char]) [1,2,3]+-- True+-- >>> alignLeftIdentity (Nothing :: Maybe Char) (Just 42)+-- True+-- >>> alignLeftIdentity ([] :: [Char]) ([] :: [Int])+-- True+alignLeftIdentity ::+  (Align f g, Eq1 f, Eq a, Eq b) =>+  f a ->+  f b ->+  Bool+alignLeftIdentity emptyX y =+  case align emptyX y of+    This t Nothing -> liftEq (==) t nil+    This t (Just (Right _)) -> liftEq (==) t nil+    _ -> False++-- | Test the empty alignment law for Align+--+-- Property: @align nil nil ≡ This nil Nothing@+--+-- This function requires proxy arguments to determine the functor and element types.+-- You can pass undefined or use type applications with @TypeApplications@.+--+-- >>> alignEmpty (undefined :: [Int]) (undefined :: [Int])+-- True+-- >>> alignEmpty (undefined :: Maybe Int) (undefined :: Maybe Int)+-- True+alignEmpty ::+  forall f g a.+  (Align f g, Eq1 f, Eq1 g, Eq a) =>+  f a ->+  f a ->+  Bool+alignEmpty _ _ =+  liftEq2 (==) (==)+    (align (nil :: f a) (nil :: f a))+    (This (nil :: f (a, a)) Nothing)++-- | Test the roundtrip law for Unalign+--+-- Property: @unalign (align xs ys) ≡ (xs, ys)@+--+-- >>> unalignRoundtrip [1,2,3] [10,20]+-- True+-- >>> unalignRoundtrip [1,2] [10,20,30]+-- True+-- >>> unalignRoundtrip (Just 1) (Just 2)+-- True+-- >>> unalignRoundtrip (Nothing :: Maybe Int) (Just 2)+-- True+unalignRoundtrip ::+  (Unalign f g, Eq1 f, Eq a, Eq b) =>+  f a ->+  f b ->+  Bool+unalignRoundtrip xs ys =+  let (xs', ys') = unalign (align xs ys)+   in liftEq (==) xs xs' && liftEq (==) ys ys'++-- | Test the naturality law for Unalign+--+-- Property: @bimap (fmap f) (fmap g) (unalign t) ≡ unalign (bimap f g t)@+--+-- >>> let t = This [(1,2),(3,4)] (Just (Left (5 :| []))) :: This [] NonEmpty Int Int+-- >>> unalignNaturality (*10) (*100) t+-- True+unalignNaturality ::+  (Unalign f g, Eq1 f, Eq c, Eq d) =>+  (a -> c) ->+  (b -> d) ->+  This f g a b ->+  Bool+unalignNaturality f g t =+  let (as, bs) = unalign t+      (as', bs') = unalign (bimap f g t)+   in liftEq (==) (fmap f as) as' && liftEq (==) (fmap g bs) bs'++-- | Lens focusing on the matched pairs component+--+-- >>> import Control.Lens (view, set)+-- >>> view these (This [(1,2),(3,4)] Nothing :: This [] NonEmpty Int Int)+-- [(1,2),(3,4)]+-- >>> set these [(5,6)] (This [(1,2)] Nothing :: This [] NonEmpty Int Int)+-- This [(5,6)] Nothing+these :: Lens (This f g a b) (This f' g a b) (f (a, b)) (f' (a, b))+these f (This e o) = fmap (`This` o) (f e)+{-# INLINE these #-}++-- | Lens focusing on the leftover component+--+-- >>> import Control.Lens (view, set)+-- >>> view those (This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int)+-- Just (Left (3 :| []))+-- >>> set those (Nothing :: Maybe (Either (NonEmpty Int) (NonEmpty Int))) (This [(1,2)] (Just (Left (3 :| []))) :: This [] NonEmpty Int Int)+-- This [(1,2)] Nothing+those :: Lens (This f g a b) (This f g' a b) (Maybe (Either (g a) (g b))) (Maybe (Either (g' a) (g' b)))+those f (This e o) = fmap (This e) (f o)+{-# INLINE those #-}++-- | Traversal focusing on left leftovers+--+-- >>> import Control.Lens (view, toListOf)+-- >>> toListOf thoseLeft (This [(1,2)] (Just (Left (3 :| [4]))) :: This [] NonEmpty Int Int)+-- [3 :| [4]]+-- >>> toListOf thoseLeft (This [(1,2)] (Just (Right (3 :| [4]))) :: This [] NonEmpty Int Int)+-- []+thoseLeft :: Traversal' (This f g a b) (g a)+thoseLeft = those . traverse . _Left+{-# INLINE thoseLeft #-}++-- | Traversal focusing on right leftovers+--+-- >>> import Control.Lens (toListOf)+-- >>> toListOf thoseRight (This [(1,2)] (Just (Right (3 :| [4]))) :: This [] NonEmpty Int Int)+-- [3 :| [4]]+-- >>> toListOf thoseRight (This [(1,2)] (Just (Left (3 :| [4]))) :: This [] NonEmpty Int Int)+-- []+thoseRight :: Traversal' (This f g a b) (g b)+thoseRight = those . traverse . _Right+{-# INLINE thoseRight #-}++-- | Traversal focusing on all 'a' values in This+-- Touches 'a' in the tuples (a,b) and in Left (g a)+--+-- >>> import Control.Lens (over, toListOf)+-- >>> over traverseA (*10) (This [(1,2),(3,4)] Nothing :: This [] NonEmpty Int Int)+-- This [(10,2),(30,4)] Nothing+-- >>> over traverseA (*10) (This [(1,2)] (Just (Left (3 :| [4]))) :: This [] NonEmpty Int Int)+-- This [(10,2)] (Just (Left (30 :| [40])))+-- >>> toListOf traverseA (This [(1,2),(3,4)] (Just (Left (5 :| []))) :: This [] NonEmpty Int Int)+-- [1,3,5]+traverseA ::+  (Traversable f, Traversable g) =>+  Traversal (This f g a b) (This f g a' b) a a'+traverseA h (This t r) =+  This+    <$> traverse (\(a, b) -> (,b) <$> h a) t+    <*> traverse (either (fmap Left . traverse h) (pure . Right)) r+{-# INLINABLE traverseA #-}++-- | Traversal focusing on all 'b' values in This+-- Touches 'b' in the tuples (a,b) and in Right (g b)+--+-- >>> import Control.Lens (over, toListOf)+-- >>> over traverseB (*10) (This [(1,2),(3,4)] Nothing :: This [] NonEmpty Int Int)+-- This [(1,20),(3,40)] Nothing+-- >>> over traverseB (*10) (This [(1,2)] (Just (Right (3 :| [4]))) :: This [] NonEmpty Int Int)+-- This [(1,20)] (Just (Right (30 :| [40])))+-- >>> toListOf traverseB (This [(1,2),(3,4)] (Just (Right (5 :| []))) :: This [] NonEmpty Int Int)+-- [2,4,5]+traverseB ::+  (Traversable f, Traversable g) =>+  Traversal (This f g a b) (This f g a b') b b'+traverseB h (This t r) =+  This+    <$> traverse (\(a, b) -> (a,) <$> h b) t+    <*> traverse (either (pure . Left) (fmap Right . traverse h)) r+{-# INLINABLE traverseB #-}++-- | Traversal1 focusing on all 'a' values in This (at least one)+-- Uses Apply instead of Applicative+--+-- >>> import Control.Lens (over)+-- >>> over traverseA1 (*10) (This ((1,2) :| [(3,4)]) Nothing :: This NonEmpty NonEmpty Int Int)+-- This ((10,2) :| [(30,4)]) Nothing+-- >>> over traverseA1 (*10) (This ((1,2) :| []) (Just (Left (3 :| [4]))) :: This NonEmpty NonEmpty Int Int)+-- This ((10,2) :| []) (Just (Left (30 :| [40])))+traverseA1 ::+  (Traversable1 f, Traversable1 g) =>+  Traversal1 (This f g a b) (This f g a' b) a a'+traverseA1 h (This t r) =+  let tResult = traverse1 (\(a, b) -> (,b) <$> h a) t+   in case r of+        Nothing -> (`This` Nothing) <$> tResult+        Just (Left ga) -> (\t' ga' -> This t' (Just (Left ga'))) <$> tResult <.> traverse1 h ga+        Just (Right gb) -> (\t' -> This t' (Just (Right gb))) <$> tResult+{-# INLINABLE traverseA1 #-}++-- | Traversal1 focusing on all 'b' values in This (at least one)+-- Uses Apply instead of Applicative+--+-- >>> import Control.Lens (over)+-- >>> over traverseB1 (*10) (This ((1,2) :| [(3,4)]) Nothing :: This NonEmpty NonEmpty Int Int)+-- This ((1,20) :| [(3,40)]) Nothing+-- >>> over traverseB1 (*10) (This ((1,2) :| []) (Just (Right (3 :| [4]))) :: This NonEmpty NonEmpty Int Int)+-- This ((1,20) :| []) (Just (Right (30 :| [40])))+traverseB1 ::+  (Traversable1 f, Traversable1 g) =>+  Traversal1 (This f g a b) (This f g a b') b b'+traverseB1 h (This t r) =+  let tResult = traverse1 (\(a, b) -> (a,) <$> h b) t+   in case r of+        Nothing -> (`This` Nothing) <$> tResult+        Just (Left ga) -> (\t' -> This t' (Just (Left ga))) <$> tResult+        Just (Right gb) -> (\t' gb' -> This t' (Just (Right gb'))) <$> tResult <.> traverse1 h gb+{-# INLINABLE traverseB1 #-}++-- | Fold optic over all 'a' values in This+--+-- >>> import Control.Lens (toListOf)+-- >>> toListOf foldA (This [(1,2),(3,4)] Nothing :: This [] NonEmpty Int Int)+-- [1,3]+-- >>> toListOf foldA (This [(1,2)] (Just (Left (3 :| [4]))) :: This [] NonEmpty Int Int)+-- [1,3,4]+-- >>> toListOf foldA (This [(1,2)] (Just (Right (3 :| [4]))) :: This [] NonEmpty Int Int)+-- [1]+foldA :: (Foldable f, Foldable g) => Fold (This f g a b) a+foldA h x@(This t r) =+  x <$ (traverse_ (\(a, _) -> h a) t <* traverse_ (either (traverse_ h) (pure (pure ()))) r)+{-# INLINE foldA #-}++-- | Fold optic over all 'b' values in This+--+-- >>> import Control.Lens (toListOf)+-- >>> toListOf foldB (This [(1,2),(3,4)] Nothing :: This [] NonEmpty Int Int)+-- [2,4]+-- >>> toListOf foldB (This [(1,2)] (Just (Right (3 :| [4]))) :: This [] NonEmpty Int Int)+-- [2,3,4]+-- >>> toListOf foldB (This [(1,2)] (Just (Left (3 :| [4]))) :: This [] NonEmpty Int Int)+-- [2]+foldB :: (Foldable f, Foldable g) => Fold (This f g a b) b+foldB h x@(This t r) =+  x <$ (traverse_ (\(_, b) -> h b) t <* traverse_ (either (pure (pure ())) (traverse_ h)) r)+{-# INLINE foldB #-}++-- | Fold1 optic over all 'a' values in This (at least one)+--+-- >>> import Control.Lens (toListOf)+-- >>> toListOf foldA1 (This ((1,2) :| [(3,4)]) Nothing :: This NonEmpty NonEmpty Int Int)+-- [1,3]+-- >>> toListOf foldA1 (This ((1,2) :| []) (Just (Left (3 :| [4]))) :: This NonEmpty NonEmpty Int Int)+-- [1,3,4]+foldA1 :: (Foldable1 f, Foldable1 g) => Fold1 (This f g a b) a+foldA1 h x@(This t r) =+  let ese = traverse1_ (\(a, _) -> h a) t+   in x <$ case r of+        Nothing -> ese+        Just (Left ga) -> ese .> traverse1_ h ga+        Just (Right _) -> ese+{-# INLINE foldA1 #-}++-- | Fold1 optic over all 'b' values in This (at least one)+--+-- >>> import Control.Lens (toListOf)+-- >>> toListOf foldB1 (This ((1,2) :| [(3,4)]) Nothing :: This NonEmpty NonEmpty Int Int)+-- [2,4]+-- >>> toListOf foldB1 (This ((1,2) :| []) (Just (Right (3 :| [4]))) :: This NonEmpty NonEmpty Int Int)+-- [2,3,4]+foldB1 :: (Foldable1 f, Foldable1 g) => Fold1 (This f g a b) b+foldB1 h x@(This t r) =+  let ese = traverse1_ (\(_, b) -> h b) t+   in x <$ case r of+        Nothing -> ese+        Just (Left _) -> ese+        Just (Right gb) -> ese .> traverse1_ h gb+{-# INLINE foldB1 #-}++-- | Traverse with at least one element, discarding results+-- Uses Apply to combine effects+--+-- >>> traverse1_ Just (1 :| [2,3])+-- Just ()+traverse1_ :: (Foldable1 t, Apply f) => (a -> f b) -> t a -> f ()+traverse1_ f xs = case toNonEmpty xs of+  (x :| []) -> f x $> ()+  (x :| (y : ys)) -> f x .> traverse1_ f (y :| ys)+  where+    toNonEmpty = foldMap1 (:| [])+{-# INLINABLE traverse1_ #-}
+ test/Main.hs view
@@ -0,0 +1,17 @@+module Main where++import System.Exit (exitWith)+import System.Process (rawSystem)++main :: IO ()+main =+  exitWith+    =<< rawSystem+      "cabal"+      [ "repl",+        "--with-compiler=doctest",+        "--repl-options=-w",+        "--repl-options=-Wdefault",+        "--repl-options=-Wno-inline-rule-shadowing",+        "lib:alignment"+      ]