{-# LANGUAGE AllowAmbiguousTypes   #-}
{-# LANGUAGE ConstraintKinds       #-}
{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE DeriveGeneric         #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
       {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE PolyKinds             #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeApplications      #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE TypeOperators         #-}
{-# LANGUAGE UndecidableInstances  #-}
{-# LANGUAGE UndecidableSuperClasses #-}
{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
{-|
Module      : Frames.Aggregation.General
Description : A specialised Map/Reduce for aggregating one set of keys to a smaller one given some operation to merge data. 
Copyright   : (c) Adam Conner-Sax 2019
License     : BSD
Maintainer  : adam_conner_sax@yahoo.com
Stability   : experimental

Frames.Aggregation.General contains types and functions to support a specific map/reduce operation.  Frequently, data is given
with more specificity than required for downstream operations.  Perhaps an age is given in years and we only need to know the
age-band.  Assuming we know how to aggregagte data columns, we want to perform that aggregation on all the subsets required to
build the data-set with the simpler key, while perhaps leaving some other columns alone.  @aggregateFold@ does this.
-}
module Frames.Aggregation.General
  (
  -- * Type-alias for maps from one record key to another
    RecordKeyMap
    -- * Aggregation Function combinators
  , combineKeyAggregations
  , keyMap
    -- * aggregationFolds
  , aggregateAllFold
  , aggregateFold
  , mergeDataFolds
  )
where

import           Frames.MapReduce.General       ( RecGetFieldC(..)
                                                , RCastC(..)
                                                , IsoRec(..)
                                                , isoRecAppend
                                                )

import qualified Control.MapReduce             as MR
import qualified Frames.MapReduce.General      as FMR

import qualified Control.Foldl                 as FL

import qualified Frames                        as F
import qualified Frames.Melt                   as F
import qualified Data.Vinyl                    as V
import qualified Data.Vinyl.TypeLevel          as V

import           Data.Vinyl                     ( ElField )
import qualified Data.Vinyl.Functor            as V
import           Frames                         ( (:.) )

import           GHC.TypeLits                   ( Symbol )
import           Data.Kind                      ( Type )

-- | Type-alias for key aggregation functions.
type RecordKeyMap record f k k' = record (f :. ElField) k -> record (f :. ElField) k'

-- | Combine 2 key aggregation functions over disjoint columns.
combineKeyAggregations
  :: forall (a :: [(Symbol, Type)]) b a' b' record f
   . ( a F.⊆ (a V.++ b)
     , b F.⊆ (a V.++ b)
     , F.Disjoint a' b' ~ 'True
     , RCastC a (a V.++ b) record f
     , RCastC b (a V.++ b) record f
     , IsoRec a' record f
     , IsoRec b' record f
     , IsoRec (a' V.++ b') record f
     )
  => RecordKeyMap record f a a'
  -> RecordKeyMap record f b b'
  -> RecordKeyMap record f (a V.++ b) (a' V.++ b')
combineKeyAggregations :: RecordKeyMap record f a a'
-> RecordKeyMap record f b b'
-> RecordKeyMap record f (a ++ b) (a' ++ b')
combineKeyAggregations RecordKeyMap record f a a'
aToa' RecordKeyMap record f b b'
bTob' record (f :. ElField) (a ++ b)
r =
  RecordKeyMap record f a a'
aToa' (record (f :. ElField) (a ++ b) -> record (f :. ElField) a
forall k (rs :: k) (ss :: k)
       (record :: ((Symbol, *) -> *) -> k -> *) (f :: * -> *).
RCastC rs ss record f =>
record (f :. ElField) ss -> record (f :. ElField) rs
rcastF record (f :. ElField) (a ++ b)
r) record (f :. ElField) a'
-> record (f :. ElField) b' -> record (f :. ElField) (a' ++ b')
forall (f :: * -> *)
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *)
       (as :: [(Symbol, *)]) (bs :: [(Symbol, *)]).
(IsoRec as record f, IsoRec bs record f,
 IsoRec (as ++ bs) record f) =>
record (f :. ElField) as
-> record (f :. ElField) bs -> record (f :. ElField) (as ++ bs)
`isoRecAppend` RecordKeyMap record f b b'
bTob' (record (f :. ElField) (a ++ b) -> record (f :. ElField) b
forall k (rs :: k) (ss :: k)
       (record :: ((Symbol, *) -> *) -> k -> *) (f :: * -> *).
RCastC rs ss record f =>
record (f :. ElField) ss -> record (f :. ElField) rs
rcastF record (f :. ElField) (a ++ b)
r)

-- | Promote an ordinary function @a -> b@ to a @RecordKeyMap aCol bCol@ where
-- @aCol@ holds values of type @a@ and @bCol@ holds values of type @b@.
keyMap
  :: forall a b record f
   . ( V.KnownField a
     , V.KnownField b
     , RecGetFieldC a record f '[a]
     , IsoRec '[b] record f
     , Applicative f
     )
  => (V.Snd a -> V.Snd b)
  -> RecordKeyMap record f '[a] '[b]
keyMap :: (Snd a -> Snd b) -> RecordKeyMap record f '[a] '[b]
keyMap Snd a -> Snd b
g record (f :. ElField) '[a]
r =
  Rec (f :. ElField) '[ '(Fst b, Snd b)]
-> record (f :. ElField) '[ '(Fst b, Snd b)]
forall (rs :: [(Symbol, *)])
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *) (f :: * -> *).
IsoRec rs record f =>
Rec (f :. ElField) rs -> record (f :. ElField) rs
fromRec
    (Rec (f :. ElField) '[ '(Fst b, Snd b)]
 -> record (f :. ElField) '[ '(Fst b, Snd b)])
-> Rec (f :. ElField) '[ '(Fst b, Snd b)]
-> record (f :. ElField) '[ '(Fst b, Snd b)]
forall a b. (a -> b) -> a -> b
$ (f (ElField '(Fst b, Snd b)) -> Compose f ElField '(Fst b, Snd b)
forall l k (f :: l -> *) (g :: k -> l) (x :: k).
f (g x) -> Compose f g x
V.Compose (f (ElField '(Fst b, Snd b)) -> Compose f ElField '(Fst b, Snd b))
-> (Compose f ElField '(Fst a, Snd a)
    -> f (ElField '(Fst b, Snd b)))
-> Compose f ElField '(Fst a, Snd a)
-> Compose f ElField '(Fst b, Snd b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ElField '(Fst a, Snd a) -> ElField '(Fst b, Snd b))
-> f (ElField '(Fst a, Snd a)) -> f (ElField '(Fst b, Snd b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Snd b -> ElField '(Fst b, Snd b)
forall (s :: Symbol) t. KnownSymbol s => t -> ElField '(s, t)
V.Field (Snd b -> ElField '(Fst b, Snd b))
-> (ElField '(Fst a, Snd a) -> Snd b)
-> ElField '(Fst a, Snd a)
-> ElField '(Fst b, Snd b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Snd a -> Snd b
g (Snd a -> Snd b)
-> (ElField '(Fst a, Snd a) -> Snd a)
-> ElField '(Fst a, Snd a)
-> Snd b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ElField '(Fst a, Snd a) -> Snd a
forall (s :: Symbol) t. ElField '(s, t) -> t
V.getField) (f (ElField '(Fst a, Snd a)) -> f (ElField '(Fst b, Snd b)))
-> (Compose f ElField '(Fst a, Snd a)
    -> f (ElField '(Fst a, Snd a)))
-> Compose f ElField '(Fst a, Snd a)
-> f (ElField '(Fst b, Snd b))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Compose f ElField '(Fst a, Snd a) -> f (ElField '(Fst a, Snd a))
forall l (f :: l -> *) k (g :: k -> l) (x :: k).
Compose f g x -> f (g x)
V.getCompose) (record (f :. ElField) '[a] -> (:.) f ElField a
forall (t :: (Symbol, *))
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *) (f :: * -> *)
       (rs :: [(Symbol, *)]).
(RecGetFieldC t record f rs, KnownField t, ElemOf rs t) =>
record (f :. ElField) rs -> (:.) f ElField t
rgetF @a record (f :. ElField) '[a]
r)
    Compose f ElField '(Fst b, Snd b)
-> Rec (f :. ElField) '[] -> Rec (f :. ElField) '[ '(Fst b, Snd b)]
forall u (a :: u -> *) (r :: u) (rs :: [u]).
a r -> Rec a rs -> Rec a (r : rs)
V.:& Rec (f :. ElField) '[]
forall u (a :: u -> *). Rec a '[]
V.RNil

-- | Given some group keys in columns k,
-- some keys to aggregate over in columns ak,
-- some keys to aggregate into in (new) columns ak',
-- a (hopefully surjective) map from records of ak to records of ak',
-- and a fold over the data, in columns d, aggregating over the rows
-- where ak was distinct but ak' is not,
-- produce a fold to transform data keyed by k and ak to data keyed
-- by k and ak' with appropriate aggregations done in the d.
-- E.g., suppose you have voter turnout data for all 50 states in the US,
-- keyed by state and age of voter in years.  The data is two columns:
-- total votes cast and turnout as a percentage.
-- You want to aggregate the ages into two bands, over and under some age.
-- So your k is the state column, ak is the age column, ak' is a new column with
-- data type to indicate over/under.  The Fold has to sum over the total votes and
-- perform a weighted-sum over the percentages.
aggregateAllFold
  :: forall (ak :: [(Symbol, Type)]) ak' d record f
   . ( (ak' V.++ d) F.⊆ ((ak V.++ d) V.++ ak')
     , ak F.⊆ (ak V.++ d)
     , ak' F.⊆ (ak' V.++ d)
     , d F.⊆ (ak' V.++ d)
     , Ord (record (f :. ElField) ak')
     , Ord (record (f :. ElField) ak)
     , RCastC (ak' V.++ d) ((ak V.++ d) V.++ ak') record f
     , RCastC ak (ak V.++ d) record f
     , RCastC ak' (ak' V.++ d) record f
     , RCastC d (ak' V.++ d) record f
     , IsoRec d record f
     , IsoRec (ak V.++ d) record f
     , IsoRec (ak' V.++ d) record f
     , IsoRec ak' record f
     , IsoRec ((ak V.++ d) V.++ ak') record f
     )
  => RecordKeyMap record f ak ak' -- ^ get aggregated key from key
  -> (FL.Fold (record (f :. ElField) d) (record (f :. ElField) d)) -- ^ aggregate data
  -> FL.Fold
       (record (f :. ElField) (ak V.++ d))
       [(record (f :. ElField) (ak' V.++ d))]
aggregateAllFold :: RecordKeyMap record f ak ak'
-> Fold (record (f :. ElField) d) (record (f :. ElField) d)
-> Fold
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
aggregateAllFold RecordKeyMap record f ak ak'
toAggKey Fold (record (f :. ElField) d) (record (f :. ElField) d)
aggDataF =
  let aggUnpack
        :: MR.Unpack
             (record (f :. ElField) (ak V.++ d))
             (record (f :. ElField) (ak' V.++ d))
      aggUnpack :: Unpack
  (record (f :. ElField) (ak ++ d))
  (record (f :. ElField) (ak' ++ d))
aggUnpack =
        (record (f :. ElField) (ak ++ d)
 -> [record (f :. ElField) (ak' ++ d)])
-> Unpack
     (record (f :. ElField) (ak ++ d))
     (record (f :. ElField) (ak' ++ d))
forall (g :: * -> *) x y. Traversable g => (x -> g y) -> Unpack x y
MR.Unpack (\record (f :. ElField) (ak ++ d)
r -> [record (f :. ElField) ((ak ++ d) ++ ak')
-> record (f :. ElField) (ak' ++ d)
forall k (rs :: k) (ss :: k)
       (record :: ((Symbol, *) -> *) -> k -> *) (f :: * -> *).
RCastC rs ss record f =>
record (f :. ElField) ss -> record (f :. ElField) rs
rcastF (record (f :. ElField) ((ak ++ d) ++ ak')
 -> record (f :. ElField) (ak' ++ d))
-> record (f :. ElField) ((ak ++ d) ++ ak')
-> record (f :. ElField) (ak' ++ d)
forall a b. (a -> b) -> a -> b
$ record (f :. ElField) (ak ++ d)
r record (f :. ElField) (ak ++ d)
-> record (f :. ElField) ak'
-> record (f :. ElField) ((ak ++ d) ++ ak')
forall (f :: * -> *)
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *)
       (as :: [(Symbol, *)]) (bs :: [(Symbol, *)]).
(IsoRec as record f, IsoRec bs record f,
 IsoRec (as ++ bs) record f) =>
record (f :. ElField) as
-> record (f :. ElField) bs -> record (f :. ElField) (as ++ bs)
`isoRecAppend` RecordKeyMap record f ak ak'
toAggKey (record (f :. ElField) (ak ++ d) -> record (f :. ElField) ak
forall k (rs :: k) (ss :: k)
       (record :: ((Symbol, *) -> *) -> k -> *) (f :: * -> *).
RCastC rs ss record f =>
record (f :. ElField) ss -> record (f :. ElField) rs
rcastF record (f :. ElField) (ak ++ d)
r)]) -- add new keys, lose old
      aggAssign :: Assign
  (record (f :. ElField) ak')
  (record (f :. ElField) (ak' ++ d))
  (record (f :. ElField) d)
aggAssign = forall (rs :: [(Symbol, *)])
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *) (f :: * -> *).
(RCastC ak' rs record f, RCastC d rs record f) =>
Assign
  (record (f :. ElField) ak')
  (record (f :. ElField) rs)
  (record (f :. ElField) d)
forall k (ks :: k) (cs :: k) (rs :: k)
       (record :: ((Symbol, *) -> *) -> k -> *) (f :: * -> *).
(RCastC ks rs record f, RCastC cs rs record f) =>
Assign
  (record (f :. ElField) ks)
  (record (f :. ElField) rs)
  (record (f :. ElField) cs)
FMR.assignKeysAndData @ak' @d
  in  Unpack
  (record (f :. ElField) (ak ++ d))
  (record (f :. ElField) (ak' ++ d))
-> Assign
     (record (f :. ElField) ak')
     (record (f :. ElField) (ak' ++ d))
     (record (f :. ElField) d)
-> Reduce
     (record (f :. ElField) ak')
     (record (f :. ElField) d)
     (record (f :. ElField) (ak' ++ d))
-> Fold
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
forall k x y c d.
Ord k =>
Unpack x y -> Assign k y c -> Reduce k c d -> Fold x [d]
MR.mapReduceFold Unpack
  (record (f :. ElField) (ak ++ d))
  (record (f :. ElField) (ak' ++ d))
aggUnpack Assign
  (record (f :. ElField) ak')
  (record (f :. ElField) (ak' ++ d))
  (record (f :. ElField) d)
aggAssign (Fold (record (f :. ElField) d) (record (f :. ElField) d)
-> Reduce
     (record (f :. ElField) ak')
     (record (f :. ElField) d)
     (record (f :. ElField) (ak' ++ d))
forall (ks :: [(Symbol, *)])
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *) (f :: * -> *)
       (cs :: [(Symbol, *)]) x.
(IsoRec ks record f, IsoRec cs record f,
 IsoRec (ks ++ cs) record f) =>
Fold x (record (f :. ElField) cs)
-> Reduce
     (record (f :. ElField) ks) x (record (f :. ElField) (ks ++ cs))
FMR.foldAndAddKey Fold (record (f :. ElField) d) (record (f :. ElField) d)
aggDataF)

-- | Aggregate key columns @ak@ into @ak'@ while leaving key columns @k@ along.
-- Allows aggregation over only some fields.  Will often require a typeapplication
-- to specify what @k@ is.
aggregateFold
  :: forall (k :: [(Symbol, Type)]) ak ak' d record f
   . ( (ak' V.++ d) F.⊆ ((ak V.++ d) V.++ ak')
     , ak F.⊆ (ak V.++ d)
     , ak' F.⊆ (ak' V.++ d)
     , d F.⊆ (ak' V.++ d)
     , Ord (record (f :. ElField) ak')
     , Ord (record (f :. ElField) ak)
     , (k V.++ (ak' V.++ d)) ~ ((k V.++ ak') V.++ d)
     , Ord (record (f :. ElField) k)
     , k F.⊆ ((k V.++ ak') V.++ d)
     , k F.⊆ ((k V.++ ak) V.++ d)
     , (ak V.++ d) F.⊆ ((k V.++ ak) V.++ d)
     , RCastC ak (ak V.++ d) record f
     , RCastC ak' (ak' V.++ d) record f
     , RCastC d (ak' V.++ d) record f
     , RCastC k ((k V.++ ak) V.++ d) record f
     , RCastC (ak V.++ d) ((k V.++ ak) V.++ d) record f
     , RCastC (ak' V.++ d) ((ak V.++ d) V.++ ak') record f
     , IsoRec k record f
     , IsoRec d record f
     , IsoRec ((k V.++ ak') V.++ d) record f
     , IsoRec (ak V.++ d) record f
     , IsoRec (ak' V.++ d) record f
     , IsoRec ak' record f
     , IsoRec ((ak V.++ d) V.++ ak') record f
     )
  => RecordKeyMap record f ak ak' -- ^ get aggregated key from key
  -> (FL.Fold (record (f :. ElField) d) (record (f :. ElField) d)) -- ^ aggregate data
  -> FL.Fold
       (record (f :. ElField) (k V.++ ak V.++ d))
       [record (f :. ElField) (k V.++ ak' V.++ d)]
aggregateFold :: RecordKeyMap record f ak ak'
-> Fold (record (f :. ElField) d) (record (f :. ElField) d)
-> Fold
     (record (f :. ElField) ((k ++ ak) ++ d))
     [record (f :. ElField) ((k ++ ak') ++ d)]
aggregateFold RecordKeyMap record f ak ak'
keyAgg Fold (record (f :. ElField) d) (record (f :. ElField) d)
aggDataF = Fold
  (record (f :. ElField) ((k ++ ak) ++ d))
  [[record (f :. ElField) ((k ++ ak') ++ d)]]
-> Fold
     (record (f :. ElField) ((k ++ ak) ++ d))
     [record (f :. ElField) ((k ++ ak') ++ d)]
forall d (g :: * -> *) a.
(Monoid d, Foldable g) =>
Fold a (g d) -> Fold a d
MR.concatFold (Fold
   (record (f :. ElField) ((k ++ ak) ++ d))
   [[record (f :. ElField) ((k ++ ak') ++ d)]]
 -> Fold
      (record (f :. ElField) ((k ++ ak) ++ d))
      [record (f :. ElField) ((k ++ ak') ++ d)])
-> Fold
     (record (f :. ElField) ((k ++ ak) ++ d))
     [[record (f :. ElField) ((k ++ ak') ++ d)]]
-> Fold
     (record (f :. ElField) ((k ++ ak) ++ d))
     [record (f :. ElField) ((k ++ ak') ++ d)]
forall a b. (a -> b) -> a -> b
$ Unpack
  (record (f :. ElField) ((k ++ ak) ++ d))
  (record (f :. ElField) ((k ++ ak) ++ d))
-> Assign
     (record (f :. ElField) k)
     (record (f :. ElField) ((k ++ ak) ++ d))
     (record (f :. ElField) (ak ++ d))
-> Reduce
     (record (f :. ElField) k)
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) ((k ++ ak') ++ d)]
-> Fold
     (record (f :. ElField) ((k ++ ak) ++ d))
     [[record (f :. ElField) ((k ++ ak') ++ d)]]
forall k x y c d.
Ord k =>
Unpack x y -> Assign k y c -> Reduce k c d -> Fold x [d]
MR.mapReduceFold
  Unpack
  (record (f :. ElField) ((k ++ ak) ++ d))
  (record (f :. ElField) ((k ++ ak) ++ d))
forall x. Unpack x x
MR.noUnpack
  (forall (rs :: [(Symbol, *)])
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *) (f :: * -> *).
(RCastC k rs record f, RCastC (ak ++ d) rs record f) =>
Assign
  (record (f :. ElField) k)
  (record (f :. ElField) rs)
  (record (f :. ElField) (ak ++ d))
forall k (ks :: k) (cs :: k) (rs :: k)
       (record :: ((Symbol, *) -> *) -> k -> *) (f :: * -> *).
(RCastC ks rs record f, RCastC cs rs record f) =>
Assign
  (record (f :. ElField) ks)
  (record (f :. ElField) rs)
  (record (f :. ElField) cs)
FMR.assignKeysAndData @k @(ak V.++ d))
  ( (record (f :. ElField) (ak' ++ d)
 -> record (f :. ElField) (ak' ++ d))
-> Reduce
     (record (f :. ElField) k)
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
-> Reduce
     (record (f :. ElField) k)
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (k ++ (ak' ++ d))]
forall (g :: * -> *) (ks :: [(Symbol, *)])
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *) (f :: * -> *)
       (as :: [(Symbol, *)]) y x.
(Functor g, Foldable g, IsoRec ks record f, IsoRec as record f,
 IsoRec (ks ++ as) record f) =>
(y -> record (f :. ElField) as)
-> Reduce (record (f :. ElField) ks) x (g y)
-> Reduce
     (record (f :. ElField) ks) x (g (record (f :. ElField) (ks ++ as)))
FMR.makeRecsWithKey record (f :. ElField) (ak' ++ d)
-> record (f :. ElField) (ak' ++ d)
forall a. a -> a
id
  (Reduce
   (record (f :. ElField) k)
   (record (f :. ElField) (ak ++ d))
   [record (f :. ElField) (ak' ++ d)]
 -> Reduce
      (record (f :. ElField) k)
      (record (f :. ElField) (ak ++ d))
      [record (f :. ElField) (k ++ (ak' ++ d))])
-> Reduce
     (record (f :. ElField) k)
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
-> Reduce
     (record (f :. ElField) k)
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (k ++ (ak' ++ d))]
forall a b. (a -> b) -> a -> b
$ (record (f :. ElField) k
 -> Fold
      (record (f :. ElField) (ak ++ d))
      [record (f :. ElField) (ak' ++ d)])
-> Reduce
     (record (f :. ElField) k)
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
forall k x d. (k -> Fold x d) -> Reduce k x d
MR.ReduceFold (Fold
  (record (f :. ElField) (ak ++ d))
  [record (f :. ElField) (ak' ++ d)]
-> record (f :. ElField) k
-> Fold
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
forall a b. a -> b -> a
const (Fold
   (record (f :. ElField) (ak ++ d))
   [record (f :. ElField) (ak' ++ d)]
 -> record (f :. ElField) k
 -> Fold
      (record (f :. ElField) (ak ++ d))
      [record (f :. ElField) (ak' ++ d)])
-> Fold
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
-> record (f :. ElField) k
-> Fold
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
forall a b. (a -> b) -> a -> b
$ RecordKeyMap record f ak ak'
-> Fold (record (f :. ElField) d) (record (f :. ElField) d)
-> Fold
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
forall (ak :: [(Symbol, *)]) (ak' :: [(Symbol, *)])
       (d :: [(Symbol, *)])
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *) (f :: * -> *).
((ak' ++ d) ⊆ ((ak ++ d) ++ ak'), ak ⊆ (ak ++ d), ak' ⊆ (ak' ++ d),
 d ⊆ (ak' ++ d), Ord (record (f :. ElField) ak'),
 Ord (record (f :. ElField) ak),
 RCastC (ak' ++ d) ((ak ++ d) ++ ak') record f,
 RCastC ak (ak ++ d) record f, RCastC ak' (ak' ++ d) record f,
 RCastC d (ak' ++ d) record f, IsoRec d record f,
 IsoRec (ak ++ d) record f, IsoRec (ak' ++ d) record f,
 IsoRec ak' record f, IsoRec ((ak ++ d) ++ ak') record f) =>
RecordKeyMap record f ak ak'
-> Fold (record (f :. ElField) d) (record (f :. ElField) d)
-> Fold
     (record (f :. ElField) (ak ++ d))
     [record (f :. ElField) (ak' ++ d)]
aggregateAllFold RecordKeyMap record f ak ak'
keyAgg Fold (record (f :. ElField) d) (record (f :. ElField) d)
aggDataF)
  )


mergeDataFolds
  :: forall (a :: (Symbol, Type)) b d record f
   . (IsoRec '[b] record f, IsoRec '[a] record f, IsoRec '[a, b] record f)
  => FL.Fold (record (f :. ElField) d) (record (f :. ElField) '[a])
  -> FL.Fold (record (f :. ElField) d) (record (f :. ElField) '[b])
  -> FL.Fold (record (f :. ElField) d) (record (f :. ElField) '[a, b])
mergeDataFolds :: Fold (record (f :. ElField) d) (record (f :. ElField) '[a])
-> Fold (record (f :. ElField) d) (record (f :. ElField) '[b])
-> Fold (record (f :. ElField) d) (record (f :. ElField) '[a, b])
mergeDataFolds Fold (record (f :. ElField) d) (record (f :. ElField) '[a])
aF Fold (record (f :. ElField) d) (record (f :. ElField) '[b])
bF = record (f :. ElField) '[a]
-> record (f :. ElField) '[b] -> record (f :. ElField) '[a, b]
forall (f :: * -> *)
       (record :: ((Symbol, *) -> *) -> [(Symbol, *)] -> *)
       (as :: [(Symbol, *)]) (bs :: [(Symbol, *)]).
(IsoRec as record f, IsoRec bs record f,
 IsoRec (as ++ bs) record f) =>
record (f :. ElField) as
-> record (f :. ElField) bs -> record (f :. ElField) (as ++ bs)
isoRecAppend (record (f :. ElField) '[a]
 -> record (f :. ElField) '[b] -> record (f :. ElField) '[a, b])
-> Fold (record (f :. ElField) d) (record (f :. ElField) '[a])
-> Fold
     (record (f :. ElField) d)
     (record (f :. ElField) '[b] -> record (f :. ElField) '[a, b])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Fold (record (f :. ElField) d) (record (f :. ElField) '[a])
aF Fold
  (record (f :. ElField) d)
  (record (f :. ElField) '[b] -> record (f :. ElField) '[a, b])
-> Fold (record (f :. ElField) d) (record (f :. ElField) '[b])
-> Fold (record (f :. ElField) d) (record (f :. ElField) '[a, b])
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Fold (record (f :. ElField) d) (record (f :. ElField) '[b])
bF