{-# LANGUAGE TypeFamilies
,MultiParamTypeClasses
,FlexibleContexts
,FlexibleInstances
,UndecidableInstances
,Rank2Types
,DeriveDataTypeable
,ExistentialQuantification #-}-- |Monadic Iteratees:-- incremental input parsers, processors and transformersmoduleData.Iteratee.Base(-- * TypesStream(..),StreamStatus(..)-- ** Exception types,moduleData.Iteratee.Exception-- ** Iteratees,Iteratee(..)-- * Functions-- ** Control functions,run,tryRun,mapIteratee,ilift,ifold-- ** Creating Iteratees,idone,icont,liftI,idoneM,icontM-- ** Stream Functions,setEOF-- * Classes,moduleX)whereimportPreludehiding(null,catch)importData.Iteratee.ExceptionimportData.Iteratee.Base.LooseMapasXimportData.NullableasXimportData.NullPointasXimportData.MaybeimportData.MonoidimportControl.Monad(liftM,join)importControl.Monad.BaseimportControl.Monad.IO.ClassimportControl.Monad.Trans.ClassimportControl.Monad.CatchIO(MonadCatchIO(..),catch,block)importControl.Monad.Trans.ControlimportControl.Applicativehiding(empty)importControl.Exception(SomeException)importqualifiedControl.ExceptionasEimportData.Data-- |A stream is a (continuing) sequence of elements bundled in Chunks.-- The first variant indicates termination of the stream.-- Chunk a gives the currently available part of the stream.-- The stream is not terminated yet.-- The case (null Chunk) signifies a stream with no currently available-- data but which is still continuing. A stream processor should,-- informally speaking, ``suspend itself'' and wait for more data-- to arrive.dataStreamc=EOF(MaybeSomeException)|Chunkcderiving(Show,Typeable)instance(Eqc)=>Eq(Streamc)where(Chunkc1)==(Chunkc2)=c1==c2(EOFNothing)==(EOFNothing)=True(EOF(Juste1))==(EOF(Juste2))=typeOfe1==typeOfe2_==_=FalseinstanceMonoidc=>Monoid(Streamc)wheremempty=Chunkmemptymappend(EOFmErr)_=EOFmErrmappend_(EOFmErr)=EOFmErrmappend(Chunks1)(Chunks2)=Chunk(s1`mappend`s2)-- |Map a function over a stream.instanceFunctorStreamwherefmapf(Chunkxs)=Chunk$fxsfmap_(EOFmErr)=EOFmErr-- |Describe the status of a stream of data.dataStreamStatus=DataRemaining|EofNoError|EofErrorSomeExceptionderiving(Show,Typeable)-- ------------------------------------------------ create exception type hierarchy-- |Produce the 'EOF' error message. If the stream was terminated because-- of an error, keep the error message.setEOF::Streamc->SomeExceptionsetEOF(EOF(Juste))=esetEOF_=toExceptionEofException-- ------------------------------------------------ | Monadic iterateenewtypeIterateesma=Iteratee{runIter::forallr.(a->Streams->mr)->((Streams->Iterateesma)->MaybeSomeException->mr)->mr}-- ----------------------------------------------idone::a->Streams->Iterateesmaidoneas=Iteratee$\onDone_->onDoneasicont::(Streams->Iterateesma)->MaybeSomeException->Iterateesmaicontke=Iteratee$\_onCont->onContkeliftI::(Streams->Iterateesma)->IterateesmaliftIk=Iteratee$\_onCont->onContkNothing-- Monadic versions, frequently used by enumeratorsidoneM::Monadm=>a->Streams->m(Iterateesma)idoneMxstr=return$Iteratee$\onDone_->onDonexstricontM::Monadm=>(Streams->Iterateesma)->MaybeSomeException->m(Iterateesma)icontMke=return$Iteratee$\_onCont->onContkeinstance(Functorm)=>Functor(Iterateesm)wherefmapfm=Iteratee$\onDoneonCont->letod=onDone.foc=onCont.(fmapf.)inrunItermodocinstance(Functorm,Monadm,Nullables)=>Applicative(Iterateesm)wherepurex=idonex(Chunkempty){-# INLINE (<*>) #-}m<*>a=m>>=flipfmapainstance(Monadm,Nullables)=>Monad(Iterateesm)where{-# INLINE return #-}returnx=Iteratee$\onDone_->onDonex(Chunkempty){-# INLINE (>>=) #-}(>>=)=bindIteratee{-# INLINE bindIteratee #-}bindIteratee::(Monadm,Nullables)=>Iterateesma->(a->Iterateesmb)->IterateesmbbindIteratee=selfwhereselfmf=Iteratee$\onDoneonCont->letm_donea(Chunks)|nullCs=runIter(fa)onDoneonContm_doneastream=runIter(fa)(const.fliponDonestream)f_contwheref_contkNothing=runIter(kstream)onDoneonContf_contke=onContkeinrunItermm_done(onCont.(flipselff.))instanceNullPoints=>MonadTrans(Iteratees)whereliftm=Iteratee$\onDone_->m>>=fliponDone(Chunkempty)instance(MonadBasebm,Nullables,NullPoints)=>MonadBaseb(Iterateesm)whereliftBase=lift.liftBaseinstance(MonadIOm,Nullables,NullPoints)=>MonadIO(Iterateesm)whereliftIO=lift.liftIOinstance(MonadCatchIOm,Nullables,NullPoints)=>MonadCatchIO(Iterateesm)wherem`catch`f=Iteratee$\odoc->runItermodoc`catch`(\e->runIter(fe)odoc)block=iliftblockunblock=iliftunblockinstanceforalls.(NullPoints,Nullables)=>MonadTransControl(Iteratees)wherenewtypeStT(Iteratees)x=StIter{unStIter::Either(x,Streams)(MaybeSomeException)}liftWithf=lift$f$\t->liftMStIter(runItert(\xs->return$Left(x,s))(\_e->return$Righte))restoreT=join.lift.liftM(either(uncurryidone)(te.fromMaybe(iterStrExc"iteratee: error in MonadTransControl instance")).unStIter){-# INLINE liftWith #-}{-# INLINE restoreT #-}instance(MonadBaseControlbm,Nullables)=>MonadBaseControlb(Iterateesm)wherenewtypeStM(Iterateesm)a=StMIter{unStMIter::ComposeSt(Iteratees)ma}liftBaseWith=defaultLiftBaseWithStMIterrestoreM=defaultRestoreMunStMIterte::SomeException->Iterateesmatee=icont(const(tee))(Juste)-- |Send 'EOF' to the @Iteratee@ and disregard the unconsumed part of the-- stream. If the iteratee is in an exception state, that exception is-- thrown with 'Control.Exception.throw'. Iteratees that do not terminate-- on @EOF@ will throw 'EofException'.run::Monadm=>Iterateesma->maruniter=runIteriteronDoneonContwhereonDonex_=returnxonContkNothing=runIter(k(EOFNothing))onDoneonCont'onCont_(Juste)=E.throweonCont'_Nothing=E.throwEofExceptiononCont'_(Juste)=E.throwe-- |Run an iteratee, returning either the result or the iteratee exception.-- Note that only internal iteratee exceptions will be returned; exceptions-- thrown with @Control.Exception.throw@ or @Control.Monad.CatchIO.throw@ will-- not be returned.-- -- See 'Data.Iteratee.Exception.IFException' for details.tryRun::(Exceptione,Monadm)=>Iterateesma->m(Eitherea)tryRuniter=runIteriteronDoneonContwhereonDonex_=return$RightxonContkNothing=runIter(k(EOFNothing))onDoneonCont'onCont_(Juste)=return$maybeExceonCont'_Nothing=return$maybeExc(toExceptionEofException)onCont'_(Juste)=return$maybeExcemaybeExce=maybe(Left(E.throwe))Left(fromExceptione)-- |Transform a computation inside an @Iteratee@.mapIteratee::(NullPoints,Monadn,Monadm)=>(ma->nb)->Iterateesma->IterateesnbmapIterateef=lift.f.run{-# DEPRECATED mapIteratee "This function will be removed, compare to 'ilift'" #-}-- | Lift a computation in the inner monad of an iteratee.-- -- A simple use would be to lift a logger iteratee to a monad stack.-- -- > logger :: Iteratee String IO ()-- > logger = mapChunksM_ putStrLn-- > -- > loggerG :: MonadIO m => Iteratee String m ()-- > loggerG = ilift liftIO logger-- -- A more complex example would involve lifting an iteratee to work with-- interleaved streams. See the example at 'Data.Iteratee.ListLike.merge'.ilift::(Monadm,Monadn)=>(forallr.mr->nr)->Iterateesma->Iterateesnailiftfi=Iteratee$\odoc->letonDoneastr=return$Left(a,str)onContkmErr=return$Right(iliftf.k,mErr)inf(runIterionDoneonCont)>>=either(uncurryod)(uncurryoc)-- | Lift a computation in the inner monad of an iteratee, while threading-- through an accumulator.ifold::(Monadm,Monadn)=>(forallr.mr->acc->n(r,acc))->acc->Iterateesma->Iterateesn(a,acc)ifoldfacci=Iteratee$\odoc->do(r,acc')<-flipfacc$runIteri(curry$return.Left)(curry$return.Right)either(uncurry(od.flip(,)acc'))(uncurry(oc.(ifoldfacc.)))r