{-# LANGUAGE Rank2Types #-}{-# LANGUAGE FlexibleInstances #-}------------------------------------------------------------------------------- |-- Module : Data.Machine.Source-- Copyright : (C) 2012 Edward Kmett-- License : BSD-style (see the file LICENSE)---- Maintainer : Edward Kmett <ekmett@gmail.com>-- Stability : provisional-- Portability : Rank-2 Types------------------------------------------------------------------------------moduleData.Machine.Source(-- * SourcesSource ,SourceT ,source ,repeated ,cycled ,cap ,plug ,iterated ,replicated ,enumerateFromTo ,unfold ,unfoldT )whereimportControl.Monad.TransimportData.FoldableimportData.Machine.Plan importData.Machine.Type importData.Machine.Process importPrelude(Enum,Int,Maybe,Monad,($),(>>=),return)--------------------------------------------------------------------------------- Source--------------------------------------------------------------------------------- | A 'Source' never reads from its inputs.typeSource b =forallk .Machine k b -- | A 'SourceT' never reads from its inputs, but may have monadic side-effects.typeSourceT m b =forallk .MachineT m k b -- | Repeat the same value, over and over.---- This can be constructed from a plan with-- @-- repeated :: o -> Source o-- repeated = repeatedly . yield-- @---- Examples:---- >>> run $ taking 5 <~ repeated 1-- [1,1,1,1,1]--repeated::o ->Source o repeated o =loop whereloop =encased (Yield o loop )-- | Loop through a 'Foldable' container over and over.---- This can be constructed from a plan with-- @-- cycled :: Foldable f => f b -> Source b-- cycled = repeatedly (traverse_ yield xs)-- @---- Examples:---- >>> run $ taking 5 <~ cycled [1,2]-- [1,2,1,2,1]--cycled::Foldablef =>f b ->Source b cycled xs =foldrgo (cycled xs )xs wherego x m =encased $Yield x m -- | Generate a 'Source' from any 'Foldable' container.---- This can be constructed from a plan with-- @-- source :: Foldable f => f b -> Source b-- source = construct (traverse_ yield xs)-- @---- Examples:---- >>> run $ source [1,2]-- [1,2]--source::Foldablef =>f b ->Source b source =foldrgo stopped wherego x m =encased $Yield x m -- |-- You can transform a 'Source' with a 'Process'.---- Alternately you can view this as capping the 'Source' end of a 'Process',-- yielding a new 'Source'.---- @'cap' l r = l '<~' r@--cap::Process a b ->Source a ->Source b cap l r =l <~ r -- |-- You can transform any 'MachineT' into a 'SourceT', blocking its input.---- This is used by capT, and capWye, and allows an efficient way to plug-- together machines of different input languages.--plug::Monadm =>MachineT m k o ->SourceT m o plug (MachineT m )=MachineT $m >>=\x ->casex ofYield o k ->return(Yield o (plug k ))Stop ->returnStop Await __h ->runMachineT$plug h -- | 'iterated' @f x@ returns an infinite source of repeated applications-- of @f@ to @x@iterated::(a ->a )->a ->Source a iterated f x =construct (go x )wherego a =doyield a go (f a )-- | 'replicated' @n x@ is a source of @x@ emitted @n@ time(s)replicated::Int->a ->Source a replicated n x =repeated x ~> taking n -- | Enumerate from a value to a final value, inclusive, via 'succ'---- Examples:---- >>> run $ enumerateFromTo 1 3-- [1,2,3]--enumerateFromTo::Enuma =>a ->a ->Source a enumerateFromTo start end =source [start ..end ]-- | 'unfold' @k seed@ The function takes the element and returns Nothing if it-- is done producing values or returns Just (a,r), in which case, @a@ is-- 'yield'ed and @r@ is used as the next element in a recursive call.unfold::(r ->Maybe(a ,r ))->r ->Source a unfold k seed =construct (go seed )wherego r =for_(k r )$\(a ,r' )->doyield a go r' -- | Effectful 'unfold' variant.unfoldT::Monadm =>(r ->m (Maybe(a ,r )))->r ->SourceT m a unfoldT k seed =construct (go seed )wherego r =doopt <-lift$k r for_opt $\(a ,r' )->doyield a go r'