{-# LANGUAGE Rank2Types #-} {-# LANGUAGE CPP, DeriveFunctor, DeriveFoldable, DeriveTraversable, StandaloneDeriving #-} {-# LANGUAGE UndecidableInstances, FlexibleContexts, GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE EmptyCase #-} ----------------------------------------------------------------------------- -- | -- Module : Witherable -- Copyright : (c) Fumiaki Kinoshita 2020 -- License : BSD3 -- -- Maintainer : Fumiaki Kinoshita -- Stability : provisional -- Portability : non-portable -- ----------------------------------------------------------------------------- module Witherable ( Filterable(..) , (<$?>) , (<&?>) , Witherable(..) , ordNub , hashNub , forMaybe -- * Indexed variants , FilterableWithIndex(..) , WitherableWithIndex(..) -- * Wrapper , WrappedFoldable(..) ) where import Control.Applicative import Control.Applicative.Backwards (Backwards (..)) import Control.Monad.Trans.Identity import Control.Monad.Trans.Maybe import Control.Monad.Trans.State.Strict import Data.Bool (bool) import Data.Coerce (coerce) import Data.Foldable.WithIndex import Data.Functor.Compose import Data.Functor.Product as P import Data.Functor.Reverse (Reverse (..)) import Data.Functor.Sum as Sum import Data.Functor.WithIndex import Data.Functor.WithIndex.Instances () import Data.Hashable import Data.Monoid import Data.Orphans () import Data.Proxy import Data.Semigroup (Option (..)) import Data.Traversable.WithIndex import Data.Void import Prelude hiding (filter) import qualified Data.Foldable as F import qualified Data.HashMap.Lazy as HM import qualified Data.HashSet as HSet import qualified Data.IntMap.Lazy as IM import qualified Data.Map.Lazy as M import qualified Data.Maybe as Maybe import qualified Data.Sequence as S import qualified Data.Set as Set import qualified Data.Traversable as T import qualified Data.Vector as V import qualified GHC.Generics as Generics import qualified Prelude -- | Like 'Functor', but you can remove elements instead of updating them. -- -- Formally, the class 'Filterable' represents a functor from @Kleisli Maybe@ to @Hask@. -- -- A definition of 'mapMaybe' must satisfy the following laws: -- -- [/conservation/] -- @'mapMaybe' (Just . f) ≡ 'fmap' f@ -- -- [/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 mapMaybe f = catMaybes . fmap f {-# INLINE mapMaybe #-} -- | @'catMaybes' ≡ 'mapMaybe' 'id'@ catMaybes :: f (Maybe a) -> f a catMaybes = mapMaybe id {-# INLINE catMaybes #-} -- | @'filter' f . 'filter' g ≡ filter ('liftA2' ('&&') g f)@ filter :: (a -> Bool) -> f a -> f a filter f = mapMaybe $ \a -> if f a then Just a else Nothing {-# INLINE filter #-} {-# 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@ -- -- [/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, -- -- @t . 'wither' f ≡ 'wither' (t . f)@ -- -- See the @Properties.md@ file in the git distribution for some special properties of -- empty containers. 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 #-} -- | @Monadic variant of 'wither'. This may have more efficient implementation.@ witherM :: Monad m => (a -> m (Maybe b)) -> t a -> m (t b) witherM = wither filterA :: Applicative f => (a -> f Bool) -> t a -> f (t a) filterA f = wither $ \a -> (\b -> if b then Just a else Nothing) <$> f a witherMap :: (Applicative m) => (t b -> r) -> (a -> m (Maybe b)) -> t a -> m r witherMap p f = fmap p . wither f {-# INLINE witherMap #-} {-# MINIMAL #-} instance Filterable Maybe where mapMaybe f = (>>= f) {-# INLINE mapMaybe #-} instance Witherable Maybe where wither _ Nothing = pure Nothing wither f (Just a) = f a {-# INLINABLE wither #-} instance Filterable Option where mapMaybe f = (>>= Option . f) {-# INLINE mapMaybe #-} instance Witherable Option where wither f (Option x) = Option <$> wither f x {-# INLINE wither #-} -- Option doesn't have the necessary instances in Lens --instance FilterableWithIndex () Option --instance WitherableWithIndex () Option instance Monoid e => Filterable (Either e) where mapMaybe _ (Left e) = Left e mapMaybe f (Right a) = maybe (Left mempty) Right $ f a {-# INLINABLE mapMaybe #-} instance Monoid e => Witherable (Either e) where wither _ (Left e) = pure (Left e) wither f (Right a) = fmap (maybe (Left mempty) Right) (f a) {-# INLINABLE wither #-} instance Filterable [] where mapMaybe = Maybe.mapMaybe catMaybes = Maybe.catMaybes filter = Prelude.filter instance Filterable ZipList where mapMaybe f = ZipList . Maybe.mapMaybe f . getZipList catMaybes = ZipList . Maybe.catMaybes . getZipList filter f = ZipList . Prelude.filter f . getZipList -- | Methods are good consumers for fusion. instance Witherable [] where wither f = foldr go (pure []) where go x r = liftA2 (maybe id (:)) (f x) r {-# INLINE wither #-} witherM f = foldr go (pure []) where go x r = f x >>= (\z -> case z of Nothing -> r Just y -> ((:) y) <$> r ) {-# INLINE witherM #-} -- Compared to the default, this fuses an fmap into a liftA2. filterA p = go where go (x:xs) = liftA2 (bool id (x :)) (p x) (go xs) go [] = pure [] instance Witherable ZipList where wither f = fmap ZipList . wither f . getZipList instance Filterable IM.IntMap where mapMaybe = IM.mapMaybe filter = IM.filter instance Witherable IM.IntMap where instance Filterable (M.Map k) where mapMaybe = M.mapMaybe filter = M.filter instance Witherable (M.Map k) where #if MIN_VERSION_containers(0,5,8) wither f = M.traverseMaybeWithKey (const f) #endif instance (Eq k, Hashable k) => Filterable (HM.HashMap k) where mapMaybe = HM.mapMaybe filter = HM.filter instance (Eq k, Hashable k) => Witherable (HM.HashMap k) where instance Filterable Proxy where mapMaybe _ Proxy = Proxy instance Witherable Proxy where wither _ Proxy = pure Proxy instance Filterable (Const r) where mapMaybe _ (Const r) = Const r {-# INLINABLE mapMaybe #-} instance Witherable (Const r) where wither _ (Const r) = pure (Const r) {-# INLINABLE wither #-} instance Filterable V.Vector where mapMaybe = V.mapMaybe instance Witherable V.Vector where wither f = fmap V.fromList . wither f . V.toList {-# INLINABLE wither #-} instance Filterable S.Seq where mapMaybe f = S.fromList . mapMaybe f . F.toList {-# INLINABLE mapMaybe #-} filter = S.filter instance Witherable S.Seq where wither f = fmap S.fromList . wither f . F.toList {-# INLINABLE wither #-} {- -- TODO: try to figure out whether the following is better or worse for -- typical applications. It builds the sequence incrementally rather than -- building a list and converting. This is basically the same approach -- currently used by Data.Sequence.filter. witherM f = F.foldlM go S.empty where --go :: S.Seq b -> a -> m (S.Seq b) go s a = do mb <- f a case mb of Nothing -> pure s Just b -> pure $! s S.|> b {-# INLINABLE witherM #-} -} -- The instances for Compose, Product, and Sum are not entirely -- unique. Any particular composition, product, or sum of functors -- may support a variety of 'wither' implementations. instance (Functor f, Filterable g) => Filterable (Compose f g) where mapMaybe f = Compose . fmap (mapMaybe f) . getCompose filter p = Compose . fmap (filter p) . getCompose catMaybes = Compose . fmap catMaybes . getCompose instance (T.Traversable f, Witherable g) => Witherable (Compose f g) where wither f = fmap Compose . T.traverse (wither f) . getCompose witherM f = fmap Compose . T.mapM (witherM f) . getCompose filterA p = fmap Compose . T.traverse (filterA p) . getCompose instance (Filterable f, Filterable g) => Filterable (P.Product f g) where 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) 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) witherM f (P.Pair x y) = liftA2 P.Pair (witherM f x) (witherM f y) filterA p (P.Pair x y) = liftA2 P.Pair (filterA p x) (filterA p y) instance (Filterable f, Filterable g) => Filterable (Sum.Sum f g) where mapMaybe f (Sum.InL x) = Sum.InL (mapMaybe f x) mapMaybe f (Sum.InR y) = Sum.InR (mapMaybe f y) catMaybes (Sum.InL x) = Sum.InL (catMaybes x) catMaybes (Sum.InR y) = Sum.InR (catMaybes y) filter p (Sum.InL x) = Sum.InL (filter p x) filter p (Sum.InR y) = Sum.InR (filter p 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 witherM f (Sum.InL x) = Sum.InL <$> witherM f x witherM f (Sum.InR y) = Sum.InR <$> witherM f y filterA f (Sum.InL x) = Sum.InL <$> filterA f x filterA f (Sum.InR y) = Sum.InR <$> filterA f y deriving instance Filterable f => Filterable (IdentityT f) instance Witherable f => Witherable (IdentityT f) where wither f (IdentityT m) = IdentityT <$> wither f m witherM f (IdentityT m) = IdentityT <$> witherM f m filterA p (IdentityT m) = IdentityT <$> filterA p m instance Functor f => Filterable (MaybeT f) where mapMaybe f = MaybeT . fmap (mapMaybe f) . runMaybeT instance (T.Traversable t) => Witherable (MaybeT t) where wither f = fmap MaybeT . T.traverse (wither f) . runMaybeT witherM f = fmap MaybeT . T.mapM (wither f) . runMaybeT deriving instance Filterable t => Filterable (Reverse t) -- | Wither from right to left. instance Witherable t => Witherable (Reverse t) where wither f (Reverse t) = fmap Reverse . forwards $ wither (coerce f) t -- We can't do anything special with witherM, because Backwards m is not -- generally a Monad. filterA f (Reverse t) = fmap Reverse . forwards $ filterA (coerce f) t deriving instance Filterable t => Filterable (Backwards t) instance Witherable t => Witherable (Backwards t) where wither f (Backwards xs) = Backwards <$> wither f xs witherM f (Backwards xs) = Backwards <$> witherM f xs filterA f (Backwards xs) = Backwards <$> filterA f xs instance Filterable Generics.V1 where mapMaybe _ v = case v of {} catMaybes v = case v of {} filter _ v = case v of {} instance Witherable Generics.V1 where wither _ v = pure $ case v of {} filterA _ v = pure $ case v of {} instance Filterable Generics.U1 where mapMaybe _ _ = Generics.U1 catMaybes _ = Generics.U1 filter _ _ = Generics.U1 instance Witherable Generics.U1 where wither _ _ = pure Generics.U1 filterA _ _ = pure Generics.U1 instance Filterable (Generics.K1 i c) where mapMaybe _ (Generics.K1 a) = Generics.K1 a catMaybes (Generics.K1 a) = Generics.K1 a filter _ (Generics.K1 a) = Generics.K1 a instance Witherable (Generics.K1 i c) where wither _ (Generics.K1 a) = pure (Generics.K1 a) filterA _ (Generics.K1 a) = pure (Generics.K1 a) instance Filterable f => Filterable (Generics.Rec1 f) where mapMaybe f (Generics.Rec1 a) = Generics.Rec1 (mapMaybe f a) catMaybes (Generics.Rec1 a) = Generics.Rec1 (catMaybes a) filter f (Generics.Rec1 a) = Generics.Rec1 (filter f a) instance Witherable f => Witherable (Generics.Rec1 f) where wither f (Generics.Rec1 a) = fmap Generics.Rec1 (wither f a) witherM f (Generics.Rec1 a) = fmap Generics.Rec1 (witherM f a) filterA f (Generics.Rec1 a) = fmap Generics.Rec1 (filterA f a) instance Filterable f => Filterable (Generics.M1 i c f) where mapMaybe f (Generics.M1 a) = Generics.M1 (mapMaybe f a) catMaybes (Generics.M1 a) = Generics.M1 (catMaybes a) filter f (Generics.M1 a) = Generics.M1 (filter f a) instance Witherable f => Witherable (Generics.M1 i c f) where wither f (Generics.M1 a) = fmap Generics.M1 (wither f a) witherM f (Generics.M1 a) = fmap Generics.M1 (witherM f a) filterA f (Generics.M1 a) = fmap Generics.M1 (filterA f a) instance (Filterable f, Filterable g) => Filterable ((Generics.:*:) f g) where mapMaybe f (a Generics.:*: b) = mapMaybe f a Generics.:*: mapMaybe f b catMaybes (a Generics.:*: b) = catMaybes a Generics.:*: catMaybes b filter f (a Generics.:*: b) = filter f a Generics.:*: filter f b instance (Witherable f, Witherable g) => Witherable ((Generics.:*:) f g) where wither f (a Generics.:*: b) = liftA2 (Generics.:*:) (wither f a) (wither f b) witherM f (a Generics.:*: b) = liftA2 (Generics.:*:) (witherM f a) (witherM f b) filterA f (a Generics.:*: b) = liftA2 (Generics.:*:) (filterA f a) (filterA f b) instance (Filterable f, Filterable g) => Filterable ((Generics.:+:) f g) where mapMaybe f (Generics.L1 a) = Generics.L1 (mapMaybe f a) mapMaybe f (Generics.R1 a) = Generics.R1 (mapMaybe f a) catMaybes (Generics.L1 a) = Generics.L1 (catMaybes a) catMaybes (Generics.R1 a) = Generics.R1 (catMaybes a) filter f (Generics.L1 a) = Generics.L1 (filter f a) filter f (Generics.R1 a) = Generics.R1 (filter f a) instance (Witherable f, Witherable g) => Witherable ((Generics.:+:) f g) where wither f (Generics.L1 a) = fmap Generics.L1 (wither f a) wither f (Generics.R1 a) = fmap Generics.R1 (wither f a) witherM f (Generics.L1 a) = fmap Generics.L1 (witherM f a) witherM f (Generics.R1 a) = fmap Generics.R1 (witherM f a) filterA f (Generics.L1 a) = fmap Generics.L1 (filterA f a) filterA f (Generics.R1 a) = fmap Generics.R1 (filterA f a) instance (Functor f, Filterable g) => Filterable ((Generics.:.:) f g) where mapMaybe f = Generics.Comp1 . fmap (mapMaybe f) . Generics.unComp1 catMaybes = Generics.Comp1 . fmap catMaybes . Generics.unComp1 filter f = Generics.Comp1 . fmap (filter f) . Generics.unComp1 instance (T.Traversable f, Witherable g) => Witherable ((Generics.:.:) f g) where wither f = fmap Generics.Comp1 . T.traverse (wither f) . Generics.unComp1 witherM f = fmap Generics.Comp1 . T.mapM (witherM f) . Generics.unComp1 filterA f = fmap Generics.Comp1 . T.traverse (filterA f) . Generics.unComp1 -- | Indexed variant of 'Filterable'. class (FunctorWithIndex i t, Filterable t) => FilterableWithIndex i t | t -> i where imapMaybe :: (i -> a -> Maybe b) -> t a -> t b imapMaybe f = catMaybes . imap f {-# INLINE imapMaybe #-} -- | @'ifilter' f . 'ifilter' g ≡ ifilter (\i -> 'liftA2' ('&&') (f i) (g i))@ 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 -- | Effectful 'imapMaybe'. -- -- @'iwither' (\ i -> 'pure' . f i) ≡ 'pure' . 'imapMaybe' f@ iwither :: (Applicative f) => (i -> a -> f (Maybe b)) -> t a -> f (t b) iwither f = fmap catMaybes . itraverse f -- | @Monadic variant of 'wither'. This may have more efficient implementation.@ iwitherM :: (Monad m) => (i -> a -> m (Maybe b)) -> t a -> m (t b) iwitherM = iwither ifilterA :: (Applicative f) => (i -> a -> f Bool) -> t a -> f (t a) ifilterA f = iwither (\i a -> (\b -> if b then Just a else Nothing) <$> f i a) instance FilterableWithIndex () Maybe instance WitherableWithIndex () Maybe -- Option doesn't have the necessary instances in Lens --instance FilterableWithIndex () Option --instance WitherableWithIndex () Option instance FilterableWithIndex Int [] instance FilterableWithIndex Int ZipList instance WitherableWithIndex Int [] instance WitherableWithIndex Int ZipList instance FilterableWithIndex Int IM.IntMap where imapMaybe = IM.mapMaybeWithKey ifilter = IM.filterWithKey instance WitherableWithIndex Int IM.IntMap where instance FilterableWithIndex k (M.Map k) where imapMaybe = M.mapMaybeWithKey ifilter = M.filterWithKey instance WitherableWithIndex k (M.Map k) where #if MIN_VERSION_containers(0,5,8) iwither = M.traverseMaybeWithKey #endif instance (Eq k, Hashable k) => FilterableWithIndex k (HM.HashMap k) where imapMaybe = HM.mapMaybeWithKey ifilter = HM.filterWithKey instance (Eq k, Hashable k) => WitherableWithIndex k (HM.HashMap k) where instance FilterableWithIndex Void Proxy instance WitherableWithIndex Void Proxy instance FilterableWithIndex Int V.Vector where imapMaybe = V.imapMaybe ifilter = V.ifilter instance WitherableWithIndex Int V.Vector instance FilterableWithIndex Int S.Seq instance WitherableWithIndex Int S.Seq instance (FunctorWithIndex i f, FilterableWithIndex j g) => FilterableWithIndex (i, j) (Compose f g) where imapMaybe f = Compose . imap (\i -> imapMaybe (\j -> f (i, j))) . getCompose ifilter p = Compose . imap (\i -> ifilter (\j -> p (i, j))) . getCompose instance (TraversableWithIndex i f, WitherableWithIndex j g) => WitherableWithIndex (i, j) (Compose f g) where iwither f = fmap Compose . itraverse (\i -> iwither (\j -> f (i, j))) . getCompose iwitherM f = fmap Compose . imapM (\i -> iwitherM (\j -> f (i, j))) . getCompose ifilterA p = fmap Compose . itraverse (\i -> ifilterA (\j -> p (i, j))) . getCompose instance (FilterableWithIndex i f, FilterableWithIndex j g) => FilterableWithIndex (Either i j) (P.Product f g) where imapMaybe f (P.Pair x y) = P.Pair (imapMaybe (f . Left) x) (imapMaybe (f . Right) y) ifilter p (P.Pair x y) = P.Pair (ifilter (p . Left) x) (ifilter (p . Right) y) instance (WitherableWithIndex i f, WitherableWithIndex j g) => WitherableWithIndex (Either i j) (P.Product f g) where iwither f (P.Pair x y) = liftA2 P.Pair (iwither (f . Left) x) (iwither (f . Right) y) iwitherM f (P.Pair x y) = liftA2 P.Pair (iwitherM (f . Left) x) (iwitherM (f . Right) y) ifilterA p (P.Pair x y) = liftA2 P.Pair (ifilterA (p . Left) x) (ifilterA (p . Right) y) instance (FilterableWithIndex i f, FilterableWithIndex j g) => FilterableWithIndex (Either i j) (Sum.Sum f g) where imapMaybe f (Sum.InL x) = Sum.InL (imapMaybe (f . Left) x) imapMaybe f (Sum.InR y) = Sum.InR (imapMaybe (f . Right) y) ifilter f (Sum.InL x) = Sum.InL (ifilter (f . Left) x) ifilter f (Sum.InR y) = Sum.InR (ifilter (f . Right) y) instance (WitherableWithIndex i f, WitherableWithIndex j g) => WitherableWithIndex (Either i j) (Sum.Sum f g) where iwither f (Sum.InL x) = Sum.InL <$> iwither (f . Left) x iwither f (Sum.InR y) = Sum.InR <$> iwither (f . Right) y iwitherM f (Sum.InL x) = Sum.InL <$> iwitherM (f . Left) x iwitherM f (Sum.InR y) = Sum.InR <$> iwitherM (f . Right) y ifilterA f (Sum.InL x) = Sum.InL <$> ifilterA (f . Left) x ifilterA f (Sum.InR y) = Sum.InR <$> ifilterA (f . Right) y deriving instance (FilterableWithIndex i f) => FilterableWithIndex i (IdentityT f) instance (WitherableWithIndex i f) => WitherableWithIndex i (IdentityT f) where iwither f (IdentityT m) = IdentityT <$> iwither f m iwitherM f (IdentityT m) = IdentityT <$> iwitherM f m ifilterA p (IdentityT m) = IdentityT <$> ifilterA p m deriving instance FilterableWithIndex i t => FilterableWithIndex i (Reverse t) -- | Wither from right to left. instance WitherableWithIndex i t => WitherableWithIndex i (Reverse t) where iwither f (Reverse t) = fmap Reverse . forwards $ iwither (\i -> Backwards . f i) t -- We can't do anything special with iwitherM, because Backwards m is not -- generally a Monad. ifilterA p (Reverse t) = fmap Reverse . forwards $ ifilterA (\i -> Backwards . p i) t deriving instance FilterableWithIndex i t => FilterableWithIndex i (Backwards t) instance WitherableWithIndex i t => WitherableWithIndex i (Backwards t) where iwither f (Backwards xs) = Backwards <$> iwither f xs iwitherM f (Backwards xs) = Backwards <$> iwitherM f xs ifilterA f (Backwards xs) = Backwards <$> ifilterA f xs -- | An infix alias for 'mapMaybe'. The name of the operator alludes -- to '<$>', and has the same fixity. -- -- @since 0.3.1 (<$?>) :: Filterable f => (a -> Maybe b) -> f a -> f b (<$?>) = mapMaybe infixl 4 <$?> -- | Flipped version of '<$?>', the 'Filterable' version of -- 'Data.Functor.<&>'. It has the same fixity as 'Data.Functor.<&>'. -- -- @ -- ('<&?>') = 'flip' 'mapMaybe' -- @ -- -- @since 0.3.1 (<&?>) :: Filterable f => f a -> (a -> Maybe b) -> f b as <&?> f = mapMaybe f as infixl 1 <&?> -- | @'forMaybe' = 'flip' 'wither'@ forMaybe :: (Witherable t, Applicative f) => t a -> (a -> f (Maybe b)) -> f (t b) forMaybe = flip wither {-# INLINE forMaybe #-} -- | Removes duplicate elements from a list, keeping only the first -- occurrence. This is asymptotically faster than using -- 'Data.List.nub' from "Data.List". ordNub :: (Witherable t, Ord a) => t a -> t a ordNub t = evalState (witherM f t) Set.empty where f a = state $ \s -> if Set.member a s then (Nothing, s) else (Just a, Set.insert a s) {-# INLINE ordNub #-} -- | Removes duplicate elements from a list, keeping only the first -- occurrence. This is usually faster than 'ordNub', especially for -- things that have a slow comparison (like 'String'). hashNub :: (Witherable t, Eq a, Hashable a) => t a -> t a hashNub t = evalState (witherM f t) HSet.empty where f a = state $ \s -> if HSet.member a s then (Nothing, s) else (Just a, HSet.insert a s) {-# INLINE hashNub #-} -- | A default implementation for 'mapMaybe'. mapMaybeDefault :: (F.Foldable f, Alternative f) => (a -> Maybe b) -> f a -> f b mapMaybeDefault p = F.foldr (\x xs -> case p x of Just a -> pure a <|> xs _ -> xs) empty {-# INLINABLE mapMaybeDefault #-} -- | A default implementation for 'imapMaybe'. imapMaybeDefault :: (FoldableWithIndex i f, Alternative f) => (i -> a -> Maybe b) -> f a -> f b imapMaybeDefault p = ifoldr (\i x xs -> case p i x of Just a -> pure a <|> xs _ -> xs) empty {-# INLINABLE imapMaybeDefault #-} newtype WrappedFoldable f a = WrapFilterable {unwrapFoldable :: f a} deriving (Functor, F.Foldable, T.Traversable, Applicative, Alternative) instance (FunctorWithIndex i f) => FunctorWithIndex i (WrappedFoldable f) where imap f = WrapFilterable . imap f . unwrapFoldable instance (FoldableWithIndex i f) => FoldableWithIndex i (WrappedFoldable f) where ifoldMap f = ifoldMap f . unwrapFoldable instance (TraversableWithIndex i f) => TraversableWithIndex i (WrappedFoldable f) where itraverse f = fmap WrapFilterable . itraverse f . unwrapFoldable instance (F.Foldable f, Alternative f) => Filterable (WrappedFoldable f) where {-#INLINE mapMaybe#-} mapMaybe = mapMaybeDefault instance (FunctorWithIndex i f, FoldableWithIndex i f, Alternative f) => FilterableWithIndex i (WrappedFoldable f) where {-# INLINE imapMaybe #-} imapMaybe = imapMaybeDefault instance (Alternative f, T.Traversable f) => Witherable (WrappedFoldable f)