unzipWith package:hasql-interpolate

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.