Frames-map-reduce-0.2.0.0: src/Frames/MapReduce/Maybe.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
module Frames.MapReduce.Maybe
( module Frames.MapReduce.Maybe
-- , module Frames.MapReduce.General
)
where
import qualified Control.MapReduce as MR
import Control.MapReduce -- for re-export
import qualified Frames.MapReduce.General as MG
import qualified Control.Foldl as FL
import qualified Data.Foldable as F
import qualified Data.Hashable as Hash
import qualified Data.List as L
import Data.Maybe ( isJust )
import Data.Monoid ( Monoid(..) )
import Data.Hashable ( Hashable )
import qualified Frames as F
import Frames ( (:.) )
import qualified Frames.Melt as F
import qualified Frames.InCore as FI
import qualified Data.Vinyl as V
import Data.Vinyl ( ElField )
import qualified Data.Vinyl.Functor as V
import qualified Data.Vinyl.TypeLevel as V
-- | Don't do anything
unpackNoOp
:: MR.Unpack (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
unpackNoOp = MG.unpackNoOp
-- | Filter records using a function on the entire record.
unpackFilterRow
:: (record (Maybe :. ElField) rs -> Bool)
-> MR.Unpack (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
unpackFilterRow = MG.unpackFilterRow
-- | Filter records based on a condition on only one field in the row. Will usually require a Type Application to indicate which field.
unpackFilterOnField
:: forall t rs record
. (V.KnownField t, F.ElemOf rs t, MG.RecGetFieldC t record Maybe rs)
=> (Maybe (V.Snd t) -> Bool)
-> MR.Unpack
(record (Maybe :. ElField) rs)
(record (Maybe :. ElField) rs)
unpackFilterOnField = MG.unpackFilterOnField @t
-- | An unpack step which specifies a subset of columns, cs,
-- (via a type-application) and then filters a @Rec (Maybe :. Elfield) rs@
-- to only rows which have all good data in that subset.
unpackGoodRows
:: forall cs rs record
. (MG.RCastC cs rs record Maybe)
=> (record (Maybe :. ElField) cs -> Bool)
-> MR.Unpack
(record (Maybe :. ElField) rs)
(record (Maybe :. ElField) rs)
unpackGoodRows = MG.unpackGoodRows --unpackFilterRow (isJust . F.recMaybe . F.rcast @cs)
unpackGoodRecRows
:: forall cs rs record
. (MG.RCastC cs rs V.Rec Maybe)
=> MR.Unpack (V.Rec (Maybe :. ElField) rs) (V.Rec (Maybe :. ElField) rs)
unpackGoodRecRows = MG.unpackGoodRows @cs (isJust . F.recMaybe)
-- | Assign both keys and data cols. Uses type applications to specify them if they cannot be inferred.
-- Keys usually can't. Data sometimes can.
assignKeysAndData
:: forall ks cs rs record
. (MG.RCastC ks rs record Maybe, MG.RCastC cs rs record Maybe)
=> MR.Assign
(record (Maybe :. ElField) ks)
(record (Maybe :. ElField) rs)
(record (Maybe :. ElField) cs)
assignKeysAndData = MG.assignKeysAndData --MR.assign (F.rcast @ks) (F.rcast @cs)
{-# INLINABLE assignKeysAndData #-}
-- | Assign keys and leave the rest of the columns, excluding the keys, in the data passed to reduce.
splitOnKeys
:: forall ks rs cs record
. ( MG.RCastC ks rs record Maybe
, MG.RCastC cs rs record Maybe
, cs ~ F.RDeleteAll ks rs
)
=> MR.Assign
(record (Maybe :. ElField) ks)
(record (Maybe :. ElField) rs)
(record (Maybe :. ElField) cs)
splitOnKeys = assignKeysAndData @ks @cs
{-# INLINABLE splitOnKeys #-}
-- | Assign keys and leave all columns, including the keys, in the data passed to reduce.
assignKeys
:: forall ks rs record
. (MG.RCastC ks rs record Maybe)
=> MR.Assign
(record (Maybe :. ElField) ks)
(record (Maybe :. ElField) rs)
(record (Maybe :. ElField) rs)
assignKeys = MG.assignKeys
{-# INLINABLE assignKeys #-}
-- | Reduce the data to a single row and then re-attach the key.
reduceAndAddKey
:: forall ks cs x record
. ( MG.IsoRec ks record Maybe
, MG.IsoRec cs record Maybe
, MG.IsoRec (ks V.++ cs) record Maybe
, FI.RecVec ((ks V.++ cs))
)
=> (forall h . Foldable h => h x -> record (Maybe :. ElField) cs) -- ^ reduction step
-> MR.Reduce
(record (Maybe :. ElField) ks)
x
(record (Maybe :. ElField) (ks V.++ cs))
reduceAndAddKey = MG.reduceAndAddKey
{-# INLINABLE reduceAndAddKey #-}
-- | Reduce by folding the data to a single row and then re-attaching the key.
foldAndAddKey
:: ( MG.IsoRec ks record Maybe
, MG.IsoRec cs record Maybe
, MG.IsoRec (ks V.++ cs) record Maybe
, FI.RecVec ((ks V.++ cs))
)
=> FL.Fold x (record (Maybe :. ElField) cs) -- ^ reduction fold
-> MR.Reduce
(record (Maybe :. ElField) ks)
x
(record (Maybe :. ElField) (ks V.++ cs))
foldAndAddKey = MG.foldAndAddKey
{-# INLINABLE foldAndAddKey #-}
-- | Transform a reduce which produces a container of results, with a function from each result to a record,
-- into a reduce which produces a FrameRec of the result records with the key re-attached.
makeRecsWithKey
:: ( Functor g
, Foldable g
, MG.IsoRec ks record Maybe
, MG.IsoRec as record Maybe
, MG.IsoRec (ks V.++ as) record Maybe
, (FI.RecVec (ks V.++ as))
)
=> (y -> record (Maybe :. ElField) as) -- ^ map a result to a record
-> MR.Reduce (record (Maybe :. ElField) ks) x (g y) -- ^ original reduce
-> MR.Reduce
(record (Maybe :. ElField) ks)
x
(g (record (Maybe :. ElField) (ks V.++ as)))
makeRecsWithKey = MG.makeRecsWithKey
{-# INLINABLE makeRecsWithKey #-}
-- | Transform an effectful reduce which produces a container of results, with a function from each result to a record,
-- into a reduce which produces a FrameRec of the result records with the key re-attached.
makeRecsWithKeyM
:: ( Monad m
, Functor g
, Foldable g
, MG.IsoRec ks record Maybe
, MG.IsoRec as record Maybe
, MG.IsoRec (ks V.++ as) record Maybe
, (FI.RecVec (ks V.++ as))
)
=> (y -> record (Maybe :. ElField) as) -- ^ map a result to a record
-> MR.ReduceM m (record (Maybe :. ElField) ks) x (g y) -- ^ original reduce
-> MR.ReduceM
m
(record (Maybe :. ElField) ks)
x
(g (record (Maybe :. ElField) (ks V.++ as)))
makeRecsWithKeyM = MG.makeRecsWithKeyM
{-# INLINABLE makeRecsWithKeyM #-}