do
str' <- S.mapM fun1 str
str'' <- S.mapM fun2 str'
-- so on
for item in str:
item' = fun1 item
item'' = fun2 item'
-- so on
--
You received this message because you are subscribed to the Google Groups "Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-pipe...@googlegroups.com.
To post to this group, send email to haskel...@googlegroups.com.
...
import Streamingimport qualified Streaming.Prelude as S
...
(|>) = flip ($)
...
flow = items |> S.mapM (liftIO . doRequest connection) |> S.map (liftM fun1) |> S.zip fun2 |> S.filter filter1 |> S.mapM fun3
...
where flow = getItems connection |> S.filter getInteresting |> S.map fun1 |> fixItems fun2 |> S.mapM fun3 |> S.mapM fun4...
...
import qualified Control.Monad.Trans.State as ST import qualified Control.Monad.Trans.Writer as W
...
fixItems :: Monad m => FixItem e ps st -> Stream (Of e) (ST.StateT st m) Result -> Stream (Of e) (ST.StateT st m) ResultfixItems fi = loop where loop str = do e <- lift $ S.next str e' <- case e of Left err -> return err Right (e', str') -> let (fixes, problems) = W.runWriter $ fixItem fi e' fix = mconcat fixes in (lift $ ST.modify $ reportProblems fi problems e') >> case fix of ItemFix ff -> (S.yield $ ff e') ItemSkip -> pure () >> loop str' return NoResult -- FIXME how to return stream result?...
{-# LANGUAGE FlexibleContexts #-}module Main where
import Control.Monadimport Control.Monad.Trans.Readerimport Control.Monad.Trans.Stateimport Control.Monad.Trans.Writerimport Data.Functor.Identityimport Data.Traversableimport Streamingimport qualified Streaming.Prelude as S
type M = StateT [String] IO
subgen :: Int -> S.Stream (S.Of Int) M Intsubgen n = if odd n then do { return 0 } else do S.yield (n*100) S.yield (n*1000) lift $ modify (++["!!!"]) return 0
gen :: S.Stream (S.Of Int) M Intgen = do S.yield 0; S.yield 100; S.yield 101; S.yield 102; S.yield 103; S.yield 104; S.yield 105; S.yield 106 liftIO $ putStrLn "enter x: " x <- liftIO getLine let n = read x::Int S.yield n lift $ modify (++["gen1"]) lift $ modify (++["gen2"]) return 0 -- $ do
proc1 :: S.Stream (S.Of Int) M Int -> S.Stream (S.Of Int) M Intproc1 str = do st <- lift get loop str st where loop str st = do e <- lift $ S.next str e' <- case e of Left err -> return err Right (e', str') -> (if e' == 100 then (lift $ put $ st ++ ["proc1"]) else pure ()) >> subgen e' >> (S.yield $ e' + 123) >> loop str' st return 1
data Cr = Cr { crName :: String , crAge :: Int } deriving Show
data FixItem a = FixItem (a -> a) | SkipIteminstance Monoid (FixItem a) where mempty = FixItem id mappend SkipItem _ = SkipItem mappend _ SkipItem = SkipItem mappend (FixItem f) (FixItem g) = FixItem (f . g)
fixWhen :: Monad m => Bool -> m (FixItem a) -> m (FixItem a)fixWhen cond act = if cond then act else return $ FixItem id
fixcr1 :: Int -> Writer [String] (FixItem Int)fixcr1 n = let (fixes, errs) = runWriter $ sequence [ fixWhen (n == 100) (tell ["panic:"++show n++"==100"] >> return SkipItem) , fixWhen (n > 100) (tell ["err1:"++show n ++">100"] >> return (FixItem (10+))) , fixWhen (n > 1) (tell ["err2:"++show n++">1"] >> return (FixItem (100+))) ] in
writer (mconcat fixes, errs)
fixItems :: (Monad m, Num a) => Stream (Of Int) (StateT [String] m) a -> Stream (Of Int) (StateT [String] m) afixItems = loop where loop str = do e <- lift $ S.next str e' <- case e of Left err -> return err Right (e', str') -> let (fix, errs) = runWriter $ fixcr1 e' in (lift $ modify (++errs)) >> case fix of FixItem ff -> (S.yield $ ff e') SkipItem -> pure () >> loop str' return 1
(|>) = flip ($)
main :: IO ()main = do p <- runStateT flow [] print p print "end." where flow = gen |> fixItems |> S.map (+100) |> S.mapM_ (liftIO . print)
...
, transformers >= 0.5 , streaming...
> > haskell-pipes+unsubscribe@googlegroups.com
> > <mailto:haskell-pipes+unsub...@googlegroups.com>. To post to
> > this group, send email to haskel...@googlegroups.com
> > <mailto:haskell-pipes@googlegroups.com>.
>
--
Best regards,
Paul a.k.a. 6apcyk
--
You received this message because you are subscribed to the Google Groups "Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-pipes+unsubscribe@googlegroups.com.
To post to this group, send email to haskel...@googlegroups.com.
I think it's important to distinguish between two separate concepts: "fusion" vs "one-pass". "Fusion" refers to avoiding the allocation of intermediate data structures when you transform a stream multiple times whereas "one-pass" means that you don't traverse the sequence of elements twice when you transform the stream multiple times (i.e. you go over the stream in one pass). You can have a "one-pass" implementation without "fusion" but you cannot have "fusion" without a "one-pass" implementation."Fusion" is purely an optimization, meaning that whether or not an implementation uses "fusion" only affects your program's performance but won't affect its behavior. However, "one-pass" is not just an optimization: one-pass versus multiple pass changes the behavior of your program, especially once your stream has effects like in these streaming libraries.Out of the two properties, "one-pass" is *much* more important. The reason why is that "one-pass" ensures that certain functor laws hold. To see why, let's consider a case where they *don't* hold, which is `Data.List.mapM`. Normally, you mtigh expect the following functor laws to hold:Data.List.mapM (f <=< g) = Data.List.mapM f . Data.List.mapM gData.List.mapM return = idHowever, the above two laws don't actually hold for `Data.List.mapM`. For example, the first law does not hold because the order of effects are not the same for the left-hand and right-hand sides of the equation. The left-hand side of the equation interleaves the effects of `f` and `g` whereas the right-hand side runs all of `g`'s effects first followed by all of `f`'s effects. The second equation is also wrong because `Data.List.mapM` misbehaves on infinite lists:Data.List.mapM return (repeat x) = _|_id (repeat x) = repeat xThis is the root of why `Data.List.mapM` is "bad"However, the streaming libraries have their own versions of `mapM` which do obey the above functor laws. For example, if you take the `list-transformer` library and define:mapM :: (a -> m b) -> ListT m a -> ListT m bmapM f as = doa <- aslift (f a)
... then this *does* obey the following functor laws:mapM (f <=< g) = mapM f . mapM gmapM return = idFor the first equation, both sides of the equation interleave the effects of `f` and `g`. For the second equation, both sides of the equation behave correctly on infinite `ListT` streams. These functor laws hold because `ListT` is has the "one-pass" property.So to answer your question: it's not exactly the Haskell `Functor` type class per se that is important here, but the functor laws are important (for a more general notion of functor) in establishing why a single pass implementation matters.
> > <mailto:haskell-pipes+unsub...@googlegroups.com>. To post to
> > this group, send email to haskel...@googlegroups.com
> > <mailto:haskel...@googlegroups.com>.
>
--
Best regards,
Paul a.k.a. 6apcyk
--
You received this message because you are subscribed to the Google Groups "Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-pipe...@googlegroups.com.