pinch-0.3.3.0: src/Pinch/Internal/FoldList.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- |
-- Module : Pinch.Internal.FoldList
-- Copyright : (c) Abhinav Gupta 2015
-- License : BSD3
--
-- Maintainer : Abhinav Gupta <mail@abhinavg.net>
-- 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 #-}