module Fold.Effectful.Type where import Control.Applicative (Applicative, liftA2, pure, (<*>)) import Control.Monad (Monad) import Data.Functor (Functor, fmap, (<$>)) import Data.Monoid (Monoid, mempty) import Data.Semigroup (Semigroup, (<>)) import Prelude (($!)) import qualified Strict {-| Processes inputs of type @a@ and results in an effectful value of type @m b@ -} data EffectfulFold m a b = forall x. EffectfulFold { initial :: m x , step :: x -> a -> m x , extract :: x -> m b } instance Functor m => Functor (EffectfulFold m a) where fmap f EffectfulFold{ initial, step, extract } = EffectfulFold { initial , step , extract = \x -> fmap f $! extract x } instance Applicative m => Applicative (EffectfulFold m a) where pure b = EffectfulFold{ initial = pure (), step = \() _ -> pure (), extract = \() -> pure b } (<*>) EffectfulFold{ initial = initialL, step = stepL, extract = extractL } EffectfulFold{ initial = initialR, step = stepR, extract = extractR } = EffectfulFold { initial = Strict.Tuple2 <$> initialL <*> initialR , step = \(Strict.Tuple2 xL xR) a -> Strict.Tuple2 <$> stepL xL a <*> stepR xR a , extract = \(Strict.Tuple2 xL xR) -> extractL xL <*> extractR xR } instance (Semigroup b, Monad m) => Semigroup (EffectfulFold m a b) where (<>) = liftA2 (<>) instance (Monoid b, Monad m) => Monoid (EffectfulFold m a b) where mempty = pure mempty