unzipWith -package:subcategories

Unzip a sequence using a function to divide elements.
unzipWith f xs == unzip (fmap f xs)
Efficiency note: unzipWith produces its two results in lockstep. If you calculate unzipWith f xs and fully force either of the results, then the entire structure of the other one will be built as well. This behavior allows the garbage collector to collect each calculated pair component as soon as it dies, without having to wait for its mate to die. If you do not need this behavior, you may be better off simply calculating the sequence of pairs and using fmap to extract each component sequence.
Split elements in the input stream into two parts using a pure splitter function, direct each part to a different fold and zip the results. Definitions:
>>> unzipWith f = Fold.unzipWithM (return . f)

>>> unzipWith f fld1 fld2 = Fold.lmap f (Fold.unzip fld1 fld2)
This fold terminates when both the input folds terminate. Pre-release
Unzip a sequence using a function to divide elements.
unzipWith f xs == unzip (fmap f xs)
Efficiency note: unzipWith produces its two results in lockstep. If you calculate unzipWith f xs and fully force either of the results, then the entire structure of the other one will be built as well. This behavior allows the garbage collector to collect each calculated pair component as soon as it dies, without having to wait for its mate to die. If you do not need this behavior, you may be better off simply calculating the sequence of pairs and using fmap to extract each component sequence.
Unzip a vector with a function.
unzipWith f = unzip . map f
Unzipping the sequence of tuples. Since 0.7.0.0
Similar to unzipWithM but terminates when the first fold terminates.
Like unzipWith but with a monadic splitter function. Definition:
>>> unzipWithM k f1 f2 = Fold.lmapM k (Fold.unzip f1 f2)
Pre-release
Similar to unzipWithM but terminates when any fold terminates.
The continuation (forall x. (a -> x -> x) -> x -> E.Params x -> Int -> r) is given cons (a -> x -> x) and nil (x) for some existential type x and an encoder (Params x) for x. An Int is also given to tally up how many sql fields are in the unzipped structure.

Example

Consider the following manually written instance:
data Blerg = Blerg Int64 Bool Text Char

instance EncodeRow Blerg where
unzipWithEncoder k = k cons nil enc 4
where
cons (Blerg a b c d) ~(as, bs, cs, ds) =
(a : as, b : bs, c : cs, d : ds)
nil = ([], [], [], [])
enc =
(((x, _, _, _) -> x) >$< param encodeField)
<> (((_, x, _, _) -> x) >$< param encodeField)
<> (((_, _, x, _) -> x) >$< param encodeField)
<> (((_, _, _, x) -> x) >$< param encodeField)
We chose ([Int64], [Bool], [Text], [Char]) as our existential type. If we instead use the default instance based on GEncodeRow then we would produce the same code as the instance below:
instance EncodeRow Blerg where
unzipWithEncoder k = k cons nil enc 4
where
cons (Blerg a b c d) ~(~(as, bs), ~(cs, ds)) =
((a : as, b : bs), (c : cs, d : ds))
nil = (([], []), ([], []))
enc =
((((x, _),      _) -> x) >$< param encodeField)
<> ((((_, x),      _) -> x) >$< param encodeField)
<> (((_     , (x, _)) -> x) >$< param encodeField)
<> (((_     , (_, x)) -> x) >$< param encodeField)
The notable difference being we don't produce a flat tuple, but instead produce a balanced tree of tuples isomorphic to the balanced tree of :*: from the generic Rep of Blerg.