haskell-streaming / streaming

An optimized general monad transformer for streaming applications, with a simple prelude of functions
BSD 3-Clause "New" or "Revised" License
156 stars 30 forks source link

Generalize unzip, perhaps #2

Closed andrewthad closed 7 years ago

andrewthad commented 7 years ago

Original issue by @treeowl:

I don't know if this makes sense, but it should work at least for Of and (,). The constraints on f look scary, but they really boil down to f being a bifunctor that's a comonad in its second argument.

 unzip :: (Monad m, Bifunctor f, Functor (f b), Comonad (f (a,b)))
   => Stream (f (a,b)) m r -> Stream (f a) (Stream (f b) m) r
 unzip = loop where
   loop str = case str of
     Return r -> Return r
     Effect m -> Effect (liftM loop (lift m))
     Step f -> Step
              . first fst
              . extend (Effect . Step . first snd)
              . fmap (Return . loop) $ f

I don't know if the extra laziness here will cause any performance problems. If it does, and if this idea is actually good for something, we can offer both versions. As with copy, we really only need the power of Extend, not of Comonad.

treeowl commented 7 years ago

It would be interesting to see if expand is sufficient. I can definitely get the right type; have to check semantics.

treeowl commented 7 years ago

It seems that expand is sufficient, and that even the Comonad constraint is unnecessary. I can't claim to understand what's really going on, but following the types leads to this:

unzipGen :: forall m f a b r. (Monad m, Bifunctor f, Functor (f (a, b)))
         => Stream (f (a, b)) m r -> Stream (f a) (Stream (f b) m) r
unzipGen = expand $ \faxb fabx ->
                       bimap snd (const (faxb (first fst fabx))) fabx

which seems to work properly, though it looks strange. So I guess we probably don't need this function.

treeowl commented 7 years ago

We should document that both unzips and expand generalize unzip:

unzip = expand $ \p ((a, b) :> abs) -> b :> p (a :> abs)

unzip = unzips . maps (\((a,b) :> x) -> Compose (a :> (b :> x)))
treeowl commented 7 years ago

Documentation added in #16.