{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} -- | -- Module : Pinch.Internal.FoldList -- Copyright : (c) Abhinav Gupta 2015 -- License : BSD3 -- -- Maintainer : Abhinav Gupta -- Stability : experimental -- -- Implements a representation of a list as a fold over it. module Pinch.Internal.FoldList ( FoldList , map , replicate , replicateM , F.foldl' , F.foldr , F.toList , fromFoldable , fromMap , T.mapM , T.sequence ) where import Prelude hiding (foldr, map, mapM, replicate, sequence) #if __GLASGOW_HASKELL__ < 709 import Control.Applicative #endif import Control.DeepSeq (NFData (..)) import Data.Hashable (Hashable (..)) import Data.List (intercalate) import Data.Semigroup import Data.Typeable (Typeable) import qualified Control.Monad as M import qualified Data.Foldable as F import qualified Data.List as L import qualified Data.Traversable as T -- | FoldList represents a list as a @foldl'@ traversal over it. -- -- This allows us to avoid allocating new collections for an intermediate -- representation of various data types that users provide. newtype FoldList a = FoldList (forall r. (r -> a -> r) -> r -> r) deriving Typeable -- | Builds a FoldList over pairs of items of a map. fromMap :: (forall r. (r -> k -> v -> r) -> r -> m k v -> r) -- ^ @foldlWithKey@ provided by the map implementation. -> m k v -> FoldList (k, v) fromMap foldlWithKey m = FoldList (\k r -> foldlWithKey (go k) r m) where go k r a b = k r (a, b) {-# INLINE go #-} {-# INLINE fromMap #-} -- | Builds a FoldList from a Foldable. fromFoldable :: F.Foldable f => f a -> FoldList a fromFoldable l = FoldList (\k r -> F.foldl' k r l) {-# INLINE fromFoldable #-} -- | Applies the given function to all elements in the FoldList. -- -- Note that the function is applied lazily when the results are requested. If -- the results of the same FoldList are requested multiple times, the function -- will be called multiple times on the same elements. map :: (a -> b) -> FoldList a -> FoldList b map f (FoldList l) = FoldList $ \k r0 -> l (\r1 a -> k r1 (f a)) r0 {-# INLINE map #-} -- | Returns a FoldList with the given item repeated @n@ times. replicate :: Int -> a -> FoldList a replicate n a = fromFoldable (L.replicate n a) {-# INLINE replicate #-} -- | Executes the given monadic action the given number of times and returns -- a FoldList of the results. replicateM :: Monad m => Int -> m a -> m (FoldList a) replicateM n = M.liftM fromFoldable . M.replicateM n {-# INLINE replicateM #-} instance Show a => Show (FoldList a) where show l = "[" ++ intercalate ", " (F.foldr go [] l) ++ "]" where go a xs = show a:xs instance Functor FoldList where fmap = map {-# INLINE fmap #-} instance F.Foldable FoldList where foldMap f (FoldList l) = l (\r a -> r `mappend` f a) mempty {-# INLINE foldMap #-} foldl' f r (FoldList l) = l f r {-# INLINE foldl' #-} instance T.Traversable FoldList where sequenceA (FoldList f) = f (\l a -> go <$> l <*> a) (pure (FoldList (\_ r -> r))) where go (FoldList xs) x = FoldList (\k r -> k (xs k r) x) {-# INLINE go #-} {-# INLINE sequenceA #-} instance Eq a => Eq (FoldList a) where l == r = F.toList l == F.toList r instance NFData a => NFData (FoldList a) where rnf (FoldList l) = l (\() a -> rnf a `seq` ()) () instance Hashable a => Hashable (FoldList a) where hashWithSalt s (FoldList l) = l hashWithSalt s instance Semigroup (FoldList a) where FoldList f1 <> FoldList f2 = FoldList $ \cons nil -> f2 cons (f1 cons nil) {-# INLINE (<>) #-} instance Monoid (FoldList a) where mempty = FoldList (\_ r -> r) {-# INLINE mempty #-} FoldList f1 `mappend` FoldList f2 = FoldList $ \cons nil -> f2 cons (f1 cons nil) {-# INLINE mappend #-}