Hi Michael & Gabriel,

Thanks for the replies, they are very helpful.

I had a good ol' C-style solution with IORefs (yuck), here is how it 
compares with pipes-group's "chunksOf" and Michael's faster "chunksOf":

 idiomatic way: 0.97 real 

 avoid not going down to the Proxy monad: 0.75 real 

 C style: 0.66 real

 
Is the speedup from your alternative "chunksOf" gained from not going down 
to the Proxy monad, Michael? I didn't know FreeT was that expensive.

Here is the C-style chunking code, it produces some tight loops in Core, so 
that's good. It's pretty awful though:

chunkify :: Int -> Producer a IO () -> Producer (Chunk a) IO ()
chunkify size p
  = do x <- liftIO $ startChunk size p
       case x of
         Nothing
           -> return ()
         Just (ref, p')
           -> do p''   <- liftIO (addToChunk size ref p')
                 chunk <- liftIO (readIORef ref >>= freezeChunk)
                 yield chunk
                 chunkify size p''

freezeChunk (i, v)
  = V.unsafeFreeze (VM.unsafeSlice 0 i v) >>= return . Chunk

startChunk size p
  = do x <- next p
       case x of
         Left _
           -> return Nothing
         Right (a, p')
           -> do chunk <- VM.new size
                 VM.unsafeWrite chunk 0 a
                 ref   <- liftIO $ newIORef (1,chunk)
                 return $ Just (ref, p')

addToChunk size ref p
  = do x <- next p
       case x of
         Left _
           -> return p
         Right (a, p')
           -> do (i, chunk) <- readIORef ref
                 VM.unsafeWrite chunk i a
                 writeIORef ref (i+1, chunk)
                 if   i + 1 >= size
                 then return p'
                 else addToChunk size ref p'

Even this code is not as fast as I expected it to be, which is strange to 
me =/

Thanks again,

Tran

On Thursday, 6 August 2015 14:35:20 UTC+10, Michael Thompson wrote:
>
> I noticed that `chunksOf` involves a very complicated double use of `next` 
> (it uses
> `splitAt` which is also defined with `next`). `next` basically forces each 
> step into the
> base monad. 
>
> It's not a miracle, but if I reimplement `chunksOf` using Pipes.Internal 
> explicitly, 
> the 'idiomatic' program goes from
>
>     real 0m0.209s
>
> to 
>
>     real 0m0.097s
>
> (I was chunking at 10 for some reason) Not too bad. Does this work better 
> for you Tran?
>
>     import qualified  Pipes.Internal as I 
>
>     chunksOf
>         :: Monad m => Int 
>         -> Lens (Producer a' m x) (Producer a m x) 
>                 (FreeT (Producer a' m) m x) (FreeT (Producer a m) m x)
>     chunksOf n0 k p0 = fmap concats (k (_chunksOf_ p0))
>       where
>       _chunksOf_ p = case p of
>           I.Pure r       -> return r
>           I.Request v _  -> I.closed v
>           I.M         m  -> FreeT $ m >>= runFreeT . _chunksOf_
>           x              -> FreeT $ return $ Free $ fmap _chunksOf_ (to n0 
> x)
>       to n p =
>           if n <= 0
>           then I.Pure p
>           else case p of
>             I.Pure r       -> return (return r)
>             I.Request v _  -> I.closed v
>             I.M         m  -> I.M $ liftM (to n) m
>             I.Respond a f  -> I.Respond a (to (n-1) . f)
>
> `to n` there is `view (splitAt n)` which would presumably be a little 
> better, 
> when used by itself, if it were written without `next`.
>
>
>
>
>

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to haskell-pipes@googlegroups.com.

Reply via email to