{-# LANGUAGE FunctionalDependencies, FlexibleInstances, MultiParamTypeClasses #-}-- |A monad for consuming streams - I believe this is basically just a specialized version of the State monad. moduleControl.Monad.ConsumerwhereimportControl.ApplicativeimportControl.MonadimportControl.Monad.FiximportControl.Monad.Trans-- * Consumer MonadnewtypeConsumerca=Consumer([c]->(a,[c]))-- | Execute a stateful computation, as a result we get-- the result of the computation, and the final state.runConsumer::[c]->Consumerca->(a,[c])runConsumerc(Consumerm)=mc-- | Execute a stateful computation, ignoring the final state.evalConsumer::[c]->Consumerca->aevalConsumercm=fst(runConsumercm)-- | Execute a stateful computation, just for the side effect.execConsumer::[c]->Consumerca->[c]execConsumercm=snd(runConsumercm)instanceFunctor(Consumerc)wherefmapf(Consumerm)=Consumer(\c->let(a,c1)=mcin(fa,c1))instanceMonad(Consumerc)wherereturna=Consumer(\c->(a,c))Consumerm>>=k=Consumer(\c->let(a,c1)=mcConsumern=kainnc1)instanceMonadFix(Consumerc)wheremfixf=Consumer(\c->letConsumerm=f(fstr)r=mcinr)class(Monadm)=>MonadConsumermc|m->cwherenext::(Monadm')=>m(m'c)-- ^ return next element from streampeek::(Monadm')=>m(m'c)-- ^ peek at next element, but leave it in the streampoke::c->mc-- ^ push and element onto the beginning on the streaminstanceMonadConsumer(Consumerc)cwherenext=Consumer$\cs->casecsof[]->(fail"end of stream",[])(c:rest)->(returnc,rest)peek=Consumer$\cs->casecsof[]->(fail"end of stream",[])cs@(c:_)->(returnc,cs)pokec=Consumer$\cs->(c,c:cs)instanceApplicative(Consumera)wherepure=return(<*>)=ap-- * Consumer Monad TransformernewtypeConsumerTcma=ConsumerT{runConsumerT::[c]->m(a,[c])}instance(Monadm)=>Functor(ConsumerTcm)wherefmapfm=ConsumerT$\c->do(x,c')<-runConsumerTmcreturn(fx,c')instance(Monadm)=>Monad(ConsumerTcm)wherereturna=ConsumerT$\c->return(a,c)m>>=k=ConsumerT$\c->do(a,c')<-runConsumerTmcrunConsumerT(ka)c'failstr=ConsumerT$\_->failstrinstance(MonadPlusm)=>MonadPlus(ConsumerTcm)wheremzero=liftmzeromplusm1m2=ConsumerT$\c->letm1'=(runConsumerTm1)cm2'=(runConsumerTm2)cinmplusm1'm2'instance(Monadm)=>MonadConsumer(ConsumerTcm)cwherenext=ConsumerT$\cs->casecsof[]->return(fail"End of Stream",[])(c:rest)->return(returnc,rest)peek=ConsumerT$\cs->casecsof[]->return(fail"End of Stream",[])cs@(c:_)->return(returnc,cs)pokec=ConsumerT$\cs->return(c,c:cs)instanceMonadTrans(ConsumerTc)whereliftm=ConsumerT$\c->doa<-mreturn(a,c)instance(MonadIOm)=>MonadIO(ConsumerTcm)whereliftIO=lift.liftIOinstance(Monadm)=>Applicative(ConsumerTcm)wherepure=return(<*>)=ap