packages feed

witherable 0.4.1 → 0.5

raw patch · 5 files changed

Files

CHANGELOG.md view
@@ -1,3 +1,17 @@+0.5+---++* `FilterableWithIndex` is a superclass of `WitherableWithIndex`.+* Remove deprecated `Data.Witherable` module. Use `Witherable` module.+* Relax `FilterableWithIndex` composition law so list-like instances are lawful.+* Add `drain :: f a -> f b` method (with default implementation `drain = mapMaybe (Const Nothing)`) to the `Filterable`.++0.4.2+-------++* Supported GHC 9.2+* Improved the instances for `vector`+ 0.4.1 ------- * Added `ordNubBy`, `hashNubBy`, `ordNubByOf`, and `hashNubByOf`.
− src/Data/Witherable.hs
@@ -1,163 +0,0 @@-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE Trustworthy #-}--------------------------------------------------------------------------------- |--- Module      :  Data.Witherable--- Copyright   :  (c) Fumiaki Kinoshita 2015--- License     :  BSD3------ Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>--- Stability   :  provisional--- Portability :  non-portable----------------------------------------------------------------------------------module Data.Witherable {-# DEPRECATED "Use Witherable instead" #-}-  ( Filterable(..)-  , (<$?>)-  , (<&?>)-  , Witherable(..)-  , ordNub-  , ordNubOn-  , hashNub-  , hashNubOn-  , forMaybe-  -- * Indexed variants-  , FilterableWithIndex(..)-  , WitherableWithIndex(..)-  -- * Generalization-  , WitherLike, Wither, WitherLike', Wither'-  , FilterLike, Filter, FilterLike', Filter'-  , witherOf-  , forMaybeOf-  , mapMaybeOf-  , catMaybesOf-  , filterAOf-  , filterOf-  , ordNubOf-  , ordNubOnOf-  , hashNubOf-  , hashNubOnOf-   -- * Cloning-  , cloneFilter-  , Peat(..)-  -- * Wrapper-  , WrappedFoldable(..)-  ) where--import Control.Applicative-import Data.Functor.Identity-import Witherable-import qualified Data.Set as Set-import qualified Data.HashSet as HSet-import Control.Monad.Trans.State.Strict-import Data.Hashable-import Data.Coerce--type Filter s t a b = Wither s t a b-{-# DEPRECATED Filter "Use Wither instead" #-}-type FilterLike f s t a b = WitherLike f s t a b-{-# DEPRECATED FilterLike "Use WitherLike instead" #-}-type Filter' s a = Wither' s a-{-# DEPRECATED Filter' "Use Filter' instead" #-}-type FilterLike' f s a = WitherLike' f s a-{-# DEPRECATED FilterLike' "Use WitherLike' instead" #-}---- | This type allows combinators to take a 'Filter' specializing the parameter @f@.-type WitherLike f s t a b = (a -> f (Maybe b)) -> s -> f t---- | A 'Wither' is like a <http://hackage.haskell.org/package/lens-4.13.2.1/docs/Control-Lens-Type.html#t:Traversal Traversal>,--- but you can also remove targets.-type Wither s t a b = forall f. Applicative f => WitherLike f s t a b---- | A simple 'WitherLike'.-type WitherLike' f s a = WitherLike f s s a a---- | A simple 'Wither'.-type Wither' s a = forall f. Applicative f => WitherLike' f s a---- | This is used to characterize and clone a 'Filter'.--- Since @FilterLike (Peat a b) s t a b@ is monomorphic, it can be used to store a filter in a container.-newtype Peat a b t = Peat { runPeat :: forall f. Applicative f => (a -> f (Maybe b)) -> f t }--instance Functor (Peat a b) where-  fmap f (Peat k) = Peat (fmap f . k)-  {-# INLINE fmap #-}--instance Applicative (Peat a b) where-  pure a = Peat $ const (pure a)-  {-# INLINE pure #-}-  Peat f <*> Peat g = Peat $ \h -> f h <*> g h-  {-# INLINE (<*>) #-}-#if MIN_VERSION_base(4,10,0)-  liftA2 f (Peat xs) (Peat ys) = Peat $ \h -> liftA2 f (xs h) (ys h)-  {-# INLINE liftA2 #-}-#endif---- | Reconstitute a 'Filter' from its monomorphic form.-cloneFilter :: FilterLike (Peat a b) s t a b -> Filter s t a b-cloneFilter l f = (`runPeat` f) . l (\a -> Peat $ \g -> g a)-{-# INLINABLE cloneFilter #-}---- | 'witherOf' is actually 'id', but left for consistency.-witherOf :: FilterLike f s t a b -> (a -> f (Maybe b)) -> s -> f t-witherOf = id-{-# INLINE witherOf #-}---- | @'forMaybeOf' ≡ 'flip'@-forMaybeOf :: FilterLike f s t a b -> s -> (a -> f (Maybe b)) -> f t-forMaybeOf = flip-{-# INLINE forMaybeOf #-}---- In case mapMaybeOf or filterOf is called with a function of--- unknown arity, we don't want to slow things down to raise--- its arity.-idDot :: (a -> b) -> a -> Identity b-idDot = coerce---- | 'mapMaybe' through a filter.-mapMaybeOf :: FilterLike Identity s t a b -> (a -> Maybe b) -> s -> t-mapMaybeOf w f = runIdentity . w (idDot f)-{-# INLINE mapMaybeOf #-}---- | 'catMaybes' through a filter.-catMaybesOf :: FilterLike Identity s t (Maybe a) a -> s -> t-catMaybesOf w = mapMaybeOf w id-{-# INLINE catMaybesOf #-}---- | 'filterA' through a filter.-filterAOf :: Functor f => FilterLike' f s a -> (a -> f Bool) -> s -> f s-filterAOf w f = w $ \a -> (\b -> if b then Just a else Nothing) <$> f a-{-# INLINABLE filterAOf #-}---- | Filter each element of a structure targeted by a 'Filter'.-filterOf :: FilterLike' Identity s a -> (a -> Bool) -> s -> s-filterOf w f = runIdentity . filterAOf w (idDot f)-{-# INLINE filterOf #-}---- | Remove the duplicate elements through a filter.-ordNubOf :: Ord a => FilterLike' (State (Set.Set a)) s a -> s -> s-ordNubOf w = ordNubOnOf w id---- | Remove the duplicate elements through a filter.-ordNubOnOf :: Ord b => FilterLike' (State (Set.Set b)) s a -> (a -> b) -> s -> s-ordNubOnOf w p t = evalState (w f t) Set.empty-  where-    f a = let b = p a in state $ \s -> if Set.member b s-      then (Nothing, s)-      else (Just a, Set.insert b s)-{-# INLINE ordNubOf #-}---- | Remove the duplicate elements through a filter.--- It is often faster than 'ordNubOf', especially when the comparison is expensive.-hashNubOf :: (Eq a, Hashable a) => FilterLike' (State (HSet.HashSet a)) s a -> s -> s-hashNubOf w = hashNubOnOf w id---- | Remove the duplicate elements through a filter.-hashNubOnOf :: (Eq b, Hashable b) => FilterLike' (State (HSet.HashSet b)) s a -> (a -> b) -> s -> s-hashNubOnOf w p t = evalState (w f t) HSet.empty-  where-    f a = let b = p a in state $ \s -> if HSet.member b s-      then (Nothing, s)-      else (Just a, HSet.insert b s)-{-# INLINE hashNubOf #-}
src/Witherable.hs view
@@ -54,7 +54,9 @@ import Data.Monoid import Data.Orphans () import Data.Proxy+#if !MIN_VERSION_base(4,16,0) import Data.Semigroup (Option (..))+#endif import Data.Traversable.WithIndex import Data.Void import Prelude hiding (filter)@@ -68,11 +70,6 @@ import qualified Data.Set as Set import qualified Data.Traversable as T import qualified Data.Vector as V-import qualified Data.Vector.Generic as VG-import qualified Data.Vector.Fusion.Bundle as V.B-import qualified Data.Vector.Fusion.Bundle.Size as V.BS-import qualified Data.Vector.Fusion.Bundle.Monadic as V.MB-import qualified Data.Vector.Fusion.Stream.Monadic as V.MS import qualified GHC.Generics as Generics import qualified Prelude @@ -87,6 +84,7 @@ -- -- [/composition/] --   @'mapMaybe' f . 'mapMaybe' g ≡ 'mapMaybe' (f <=< g)@+-- class Functor f => Filterable f where   -- | Like 'Maybe.mapMaybe'.   mapMaybe :: (a -> Maybe b) -> f a -> f b@@ -103,33 +101,64 @@   filter f = mapMaybe $ \a -> if f a then Just a else Nothing   {-# INLINE filter #-} +  -- | Empty a filterable.+  --+  -- @'drain' ≡ 'mapMaybe' (const Nothing)@+  --+  drain :: f a -> f b+  drain = mapMaybe (const Nothing)+  {-# INLINE drain #-}+   {-# MINIMAL mapMaybe | catMaybes #-}  -- | An enhancement of 'Traversable' with 'Filterable' -- -- A definition of 'wither' must satisfy the following laws: ----- [/conservation/]---   @'wither' ('fmap' 'Just' . f) ≡ 'traverse' f@+-- [/identity/]+--   @'wither' ('Data.Functor.Identity' . Just) ≡ 'Data.Functor.Identity'@ -- -- [/composition/] --   @'Compose' . 'fmap' ('wither' f) . 'wither' g ≡ 'wither' ('Compose' . 'fmap' ('wither' f) . g)@ -- -- Parametricity implies the naturality law: ----- Whenever @t@ is an //applicative transformation// in the sense described in the--- 'Traversable' documentation,---+-- [/naturality/] --   @t . 'wither' f ≡ 'wither' (t . f)@ ----- See the @Properties.md@ file in the git distribution for some special properties of--- empty containers.+--     Where @t@ is an //applicative transformation// in the sense described in the+--     'Traversable' documentation.+-- +-- In the relation to superclasses, these should satisfy too:+--+-- [/conservation/]+--    @'wither' ('fmap' Just . f) = 'T.traverse' f@+--+-- [/pure filter/]+--    @'wither' ('Data.Functor.Identity' . f) = 'Data.Functor.Identity' . 'mapMaybe' f@+-- +-- See the @Properties.md@ and @Laws.md@ files in the git distribution for more+-- in-depth explanation about properties of @Witherable@ containers.+--+-- The laws and restrictions are enough to+-- constrain @'wither'@ to be uniquely determined as the following default implementation.+-- +-- @wither f = fmap 'catMaybes' . 'T.traverse' f@+-- +-- If not to provide better-performing implementation,+-- it's not necessary to implement any one method of+-- @Witherable@. For example, if a type constructor @T@+-- already has instances of 'T.Traversable' and 'Filterable',+-- the next one line is sufficient to provide the @Witherable T@ instance.+--+-- > instance Witherable T  class (T.Traversable t, Filterable t) => Witherable t where    -- | Effectful 'mapMaybe'.   --   -- @'wither' ('pure' . f) ≡ 'pure' . 'mapMaybe' f@+  --    wither :: Applicative f => (a -> f (Maybe b)) -> t a -> f (t b)   wither f = fmap catMaybes . T.traverse f   {-# INLINE wither #-}@@ -149,6 +178,7 @@  instance Filterable Maybe where   mapMaybe f = (>>= f)+  drain _ = Nothing   {-# INLINE mapMaybe #-}  instance Witherable Maybe where@@ -156,8 +186,11 @@   wither f (Just a) = f a   {-# INLINABLE wither #-} +#if !MIN_VERSION_base(4,16,0)+ instance Filterable Option where   mapMaybe f = (>>= Option . f)+  drain _ = Option Nothing   {-# INLINE mapMaybe #-}  instance Witherable Option where@@ -168,11 +201,16 @@ --instance FilterableWithIndex () Option --instance WitherableWithIndex () Option +#endif+ instance Monoid e => Filterable (Either e) where   mapMaybe _ (Left e) = Left e   mapMaybe f (Right a) = maybe (Left mempty) Right $ f a   {-# INLINABLE mapMaybe #-} +  drain (Left e)  = Left e+  drain (Right _) = Left mempty+ instance Monoid e => Witherable (Either e) where   wither _ (Left e) = pure (Left e)   wither f (Right a) = fmap (maybe (Left mempty) Right) (f a)@@ -182,11 +220,13 @@   mapMaybe = Maybe.mapMaybe   catMaybes = Maybe.catMaybes   filter = Prelude.filter+  drain _ = []  instance Filterable ZipList where   mapMaybe f = ZipList . Maybe.mapMaybe f . getZipList   catMaybes = ZipList . Maybe.catMaybes . getZipList   filter f = ZipList . Prelude.filter f . getZipList+  drain _ = ZipList []  -- | Methods are good consumers for fusion. instance Witherable [] where@@ -212,12 +252,14 @@ instance Filterable IM.IntMap where   mapMaybe = IM.mapMaybe   filter = IM.filter+  drain _ = IM.empty  instance Witherable IM.IntMap where  instance Filterable (M.Map k) where   mapMaybe = M.mapMaybe   filter = M.filter+  drain _ = M.empty  instance Witherable (M.Map k) where #if MIN_VERSION_containers(0,5,8)@@ -227,6 +269,7 @@ instance (Eq k, Hashable k) => Filterable (HM.HashMap k) where   mapMaybe = HM.mapMaybe   filter = HM.filter+  drain _ = HM.empty  instance (Eq k, Hashable k) => Witherable (HM.HashMap k) where @@ -247,46 +290,20 @@ instance Filterable V.Vector where   filter   = V.filter   mapMaybe = V.mapMaybe+  drain _  = V.empty  instance Witherable V.Vector where   wither f = fmap V.fromList . wither f . V.toList   {-# INLINABLE wither #-} -  witherM f = unstreamM . bundleWitherM f . V.B.lift . VG.stream+  witherM = V.mapMaybeM   {-# INLINE witherM #-} --- This is not yet in any released Vector-unstreamM :: Monad m => V.MB.Bundle m v a -> m (V.Vector a)-unstreamM s = do-  xs <- V.MB.toList s-  return $ VG.unstream $ V.B.unsafeFromList (V.MB.size s) xs-{-# INLINE unstreamM #-}--bundleWitherM :: Monad m => (a -> m (Maybe b)) -> V.MB.Bundle m v a -> V.MB.Bundle m v b-bundleWitherM g V.MB.Bundle {V.MB.sElems = s, V.MB.sSize = n} =-  V.MB.fromStream (streamWitherM g s) (V.BS.toMax n)-{-# INLINE bundleWitherM #-}--streamWitherM :: Monad m => (a -> m (Maybe b)) -> V.MS.Stream m a -> V.MS.Stream m b-streamWitherM g (V.MS.Stream step t) = V.MS.Stream step' t-  where-    {-# INLINE step' #-}-    step' s = do-      r <- step s-      case r of-        V.MS.Yield x s' -> do-          b <- g x-          case b of-            Just y  -> return $ V.MS.Yield y s'-            Nothing -> return $ V.MS.Skip    s'-        V.MS.Skip    s' -> return $ V.MS.Skip s'-        V.MS.Done       -> return $ V.MS.Done-{-# INLINE streamWitherM #-}- instance Filterable S.Seq where   mapMaybe f = S.fromList . mapMaybe f . F.toList   {-# INLINABLE mapMaybe #-}   filter = S.filter+  drain _ = S.empty  instance Witherable S.Seq where   wither f = fmap S.fromList . wither f . F.toList@@ -317,6 +334,7 @@   mapMaybe f = Compose . fmap (mapMaybe f) . getCompose   filter p = Compose . fmap (filter p) . getCompose   catMaybes = Compose . fmap catMaybes . getCompose+  drain = Compose . fmap drain . getCompose  instance (T.Traversable f, Witherable g) => Witherable (Compose f g) where   wither f = fmap Compose . T.traverse (wither f) . getCompose@@ -327,6 +345,7 @@   mapMaybe f (P.Pair x y) = P.Pair (mapMaybe f x) (mapMaybe f y)   filter p (P.Pair x y) = P.Pair (filter p x) (filter p y)   catMaybes (P.Pair x y) = P.Pair (catMaybes x) (catMaybes y)+  drain (P.Pair x y) = P.Pair (drain x) (drain y)  instance (Witherable f, Witherable g) => Witherable (P.Product f g) where   wither f (P.Pair x y) = liftA2 P.Pair (wither f x) (wither f y)@@ -343,6 +362,9 @@   filter p (Sum.InL x) = Sum.InL (filter p x)   filter p (Sum.InR y) = Sum.InR (filter p y) +  drain (Sum.InL x) = Sum.InL (drain x)+  drain (Sum.InR y) = Sum.InR (drain y)+ instance (Witherable f, Witherable g) => Witherable (Sum.Sum f g) where   wither f (Sum.InL x) = Sum.InL <$> wither f x   wither f (Sum.InR y) = Sum.InR <$> wither f y@@ -474,13 +496,13 @@   imapMaybe f = catMaybes . imap f   {-# INLINE imapMaybe #-} -  -- | @'ifilter' f . 'ifilter' g ≡ ifilter (\i -> 'liftA2' ('&&') (f i) (g i))@+  -- | @'filter' f . 'ifilter' g ≡ ifilter (\i x -> f x '&&' g i x)@   ifilter :: (i -> a -> Bool) -> t a -> t a   ifilter f = imapMaybe $ \i a -> if f i a then Just a else Nothing   {-# INLINE ifilter #-}  -- | Indexed variant of 'Witherable'.-class (TraversableWithIndex i t, Witherable t) => WitherableWithIndex i t | t -> i where+class (TraversableWithIndex i t, FilterableWithIndex i t, Witherable t) => WitherableWithIndex i t | t -> i where   -- | Effectful 'imapMaybe'.   --   -- @'iwither' (\ i -> 'pure' . f i) ≡ 'pure' . 'imapMaybe' f@@@ -673,7 +695,7 @@ hashNub = hashNubOn id {-# INLINE hashNub #-} --- | The 'hashNubOn' function behaves just like 'ordNub',+-- | The 'hashNubOn' function behaves just like 'hashNub', --   except it uses a another type to determine equivalence classes. -- -- >>> hashNubOn fst [(True, 'x'), (False, 'y'), (True, 'z')]
tests/tests.hs view
@@ -1,14 +1,19 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} module Main (main) where +import Control.Arrow (first) import Control.Monad ((<=<))-import Control.Monad.Trans.State (runState, state)+import Control.Monad.Trans.State (State, runState, state) import Data.Hashable (Hashable) import Data.Coerce (coerce) import Data.Function (on)+import Data.Functor.Compose (Compose (..)) import Data.List (nub, nubBy)+import Data.Maybe (fromMaybe) import Data.Proxy (Proxy (..)) import Data.Typeable (Typeable, typeRep) import Test.QuickCheck (Arbitrary (..), Fun, Property, applyFun, Function (..), functionMap, CoArbitrary, (===))@@ -36,6 +41,7 @@     , filterableLaws (Proxy @IntMap.IntMap)     , filterableLaws (Proxy @(Map.Map K))     , filterableLaws (Proxy @(HashMap.HashMap K))+    , filterableLaws (Proxy @Wicked)     ]    , testGroup "Witherable"@@ -44,9 +50,14 @@     , witherableLaws (Proxy @(Either String))     , witherableLaws (Proxy @V.Vector)     , witherableLaws (Proxy @Seq.Seq)+#if MIN_VERSION_containers(0,6,3)+    -- traverse @IntMap is broken     , witherableLaws (Proxy @IntMap.IntMap)+#endif     , witherableLaws (Proxy @(Map.Map K))     , witherableLaws (Proxy @(HashMap.HashMap K))+    -- Wicked is not Witherable, see https://github.com/fumieval/witherable/issues/63#issuecomment-834631975+    -- , witherableLaws (Proxy @Wicked)     ]    , nubProperties@@ -118,26 +129,60 @@   [ testProperty "default wither" prop_default_wither   , testProperty "default witherM" prop_default_witherM   , testProperty "default filterA" prop_default_filterA+  , testProperty "identity" prop_identity+  , testProperty "composition" prop_composition   ]   where     prop_default_wither :: S -> Fun (A, S) (Maybe B, S) -> f A -> Property-    prop_default_wither s0 f' xs =-        runState (wither f xs) s0 === runState (fmap catMaybes (traverse f xs)) s0+    prop_default_wither s0 f' xs = equalState s0 xs+        (wither f)+        (fmap catMaybes . traverse f)       where+        f :: A -> State S (Maybe B)         f a = state $ \s -> applyFun f' (a, s)      prop_default_witherM :: S -> Fun (A, S) (Maybe B, S) -> f A -> Property-    prop_default_witherM s0 f' xs =-        runState (witherM f xs) s0 === runState (wither f xs) s0+    prop_default_witherM s0 f' xs = equalState s0 xs+        (witherM f)+        (wither f)       where         f a = state $ \s -> applyFun f' (a, s)      prop_default_filterA :: S -> Fun (A, S) (Bool, S) -> f A -> Property-    prop_default_filterA s0 f' xs =-        runState (filterA f xs) s0 === runState (wither (\a -> (\b -> if b then Just a else Nothing) <$> f a) xs) s0+    prop_default_filterA s0 f' xs = equalState s0 xs+        (filterA f)+        (wither (\a -> (\b -> if b then Just a else Nothing) <$> f a))       where         f a = state $ \s -> applyFun f' (a, s) +    prop_identity :: S -> Fun (A, S) (B, S) -> f A -> Property+    prop_identity s0 f' xs = equalState s0 xs+        (wither (fmap Just . f))+        (traverse f)+      where+        f a = state $ \s -> applyFun f' (a, s)++    prop_composition :: S -> S -> Fun (B, S) (Maybe C, S) -> Fun (A, S) (Maybe B, S) -> f A -> Property+    prop_composition s0 s1 f' g' xs = equalStateC s0 s1 xs+         (Compose . fmap (wither f) . wither g)+         (wither (Compose . fmap (wither f) . g))+      where+        f a = state $ \s -> applyFun f' (a, s)+        g b = state $ \s -> applyFun g' (b, s)++    equalState+        :: (Eq b, Show b)+        => S -> a -> (a -> State S b) -> (a -> State S b) -> Property+    equalState s0 xs f g = runState (f xs) s0 === runState (g xs) s0++    equalStateC+        :: forall a b. (Eq b, Show b)+        => S -> S -> a -> (a -> Compose (State S) (State S) b) -> (a -> Compose (State S) (State S) b) -> Property+    equalStateC s0 s1 xs f g = run (f xs) === run (g xs)+      where+        run :: Compose (State S) (State S) b -> ((b, S), S)+        run m = first (\x -> runState x s1) (runState (getCompose m) s0)+ ------------------------------------------------------------------------------- -- Nub "laws" -------------------------------------------------------------------------------@@ -207,3 +252,22 @@  instance Function S where   function = functionMap coerce S++-------------------------------------------------------------------------------+-- Wicked+-------------------------------------------------------------------------------++newtype Wicked a = W [a]+  deriving (Eq, Show, Functor, Foldable, Traversable)++instance Filterable Wicked where+  -- mapMaybe f (W [a1,a2,...]) = W [b1, b2, ...]+  -- if all of [f a1, f a2, ...] are Just. Otherwise, it returns (W []).+  mapMaybe f = fromMaybe (W []) . traverse f++-- default implementation in terms of Filterable+instance Witherable Wicked++instance Arbitrary a => Arbitrary (Wicked a) where+    arbitrary = W <$> arbitrary+    shrink (W xs) = map W (shrink xs)
witherable.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.4 name:                witherable-version:             0.4.1+version:             0.5 synopsis:            filterable traversable description:         A stronger variant of `traverse` which can remove elements and generalised mapMaybe, catMaybes, filter homepage:            https://github.com/fumieval/witherable@@ -12,7 +12,8 @@ category:            Data build-type:          Simple extra-source-files:  CHANGELOG.md-tested-with:         GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.3+tested-with:         GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.7 ||+                         ==9.0.1 || ==9.2.8 || ==9.4.8 || ==9.6.5 || ==9.8.2 || ==9.10.1  source-repository head   type: git@@ -22,14 +23,13 @@ library   exposed-modules:     Witherable-    Data.Witherable   build-depends:       base                          >=4.9      && <5,-                       base-orphans                  >=0.8.4    && <0.9,-                       containers                    >=0.5.7.1  && <0.7,-                       hashable                      >=1.2.7.0  && <1.4,-                       transformers                  >=0.5.2.0  && <0.6,+                       base-orphans                  >=0.8.4    && <0.10,+                       containers                    >=0.5.7.1  && <0.8,+                       hashable                      >=1.2.7.0  && <1.5,+                       transformers                  >=0.5.2.0  && <0.7,                        unordered-containers          >=0.2.12.0 && <0.3,-                       vector                        >=0.12     && <0.13,+                       vector                        >=0.12.2.0 && <0.14,                        indexed-traversable           >=0.1.1    && <0.2,                        indexed-traversable-instances >=0.1      && <0.2   hs-source-dirs:      src