packages feed

Frames-map-reduce 0.1.0.1 → 0.2.0.0

raw patch · 9 files changed

+1000/−20 lines, 9 filesdep ~profunctorsPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: profunctors

API changes (from Hackage documentation)

+ Frames.Folds: FoldFieldEndo :: EndoFold (f a) -> FoldFieldEndo f a
+ Frames.Folds: [unFoldFieldEndo] :: FoldFieldEndo f a -> EndoFold (f a)
+ Frames.Folds: class (Newtype (f a) a, Monoid (f a)) => MonoidalField f a
+ Frames.Folds: fieldToFieldFold :: forall x y rs. (KnownField x, KnownField y, ElemOf rs x) => Fold (Snd x) (Snd y) -> FoldRecord ElField rs y
+ Frames.Folds: monoidWrapperToFold :: forall f a. (Newtype (f a) a, Monoid (f a)) => Fold a a
+ Frames.Folds: newtype FoldFieldEndo f a
+ Frames.Folds.General: FoldEndo :: EndoFold (f (Snd t)) -> FoldEndo f t
+ Frames.Folds.General: FoldRecord :: Fold (record (f :. ElField) rs) (g a) -> FoldRecord record f g rs a
+ Frames.Folds.General: [unFoldEndo] :: FoldEndo f t -> EndoFold (f (Snd t))
+ Frames.Folds.General: [unFoldRecord] :: FoldRecord record f g rs a -> Fold (record (f :. ElField) rs) (g a)
+ Frames.Folds.General: class (c (Snd t)) => ConstrainedField c t
+ Frames.Folds.General: class EndoFieldFoldsToRecordFolds rs record f
+ Frames.Folds.General: fieldToFieldFold :: forall x y rs record f. (KnownField x, KnownField y, ElemOf rs x, RecGetFieldC x record f rs, Applicative f) => (forall z. f z -> Maybe z) -> Fold (Snd x) (Snd y) -> FoldRecord record f (f :. ElField) rs y
+ Frames.Folds.General: foldAll :: (RPureConstrained KnownField rs, RApply rs, EndoFieldFoldsToRecordFolds rs record f, IsoRec rs record f, Functor f) => (forall a. Fold a a) -> Fold (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.Folds.General: foldAllConstrained :: forall c rs record f. (RPureConstrained (ConstrainedField c) rs, RPureConstrained KnownField rs, RApply rs, EndoFieldFoldsToRecordFolds rs record f, IsoRec rs record f, Applicative f) => (forall a. f a -> Maybe a) -> (forall a. c a => Fold a a) -> Fold (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.Folds.General: foldAllMonoid :: forall g rs record f. (RPureConstrained (ConstrainedField (MonoidalField g)) rs, RPureConstrained KnownField rs, RApply rs, EndoFieldFoldsToRecordFolds rs record f, IsoRec rs record f, Applicative f) => (forall a. f a -> Maybe a) -> Fold (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.Folds.General: functorFoldAllConstrained :: forall c rs record f. (RPureConstrained (ConstrainedField c) rs, RPureConstrained KnownField rs, RApply rs, EndoFieldFoldsToRecordFolds rs record f, IsoRec rs record f, Applicative f) => (forall a. c a => Fold (f a) (f a)) -> Fold (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.Folds.General: instance (Frames.Folds.General.EndoFieldFoldsToRecordFolds rs record f, Frames.MapReduce.General.RCastC rs (r : rs) record f, Data.Vinyl.Derived.KnownField r, Frames.MapReduce.General.RecGetFieldC r record f (r : rs), Data.Vinyl.Core.RMap rs) => Frames.Folds.General.EndoFieldFoldsToRecordFolds (r : rs) record f
+ Frames.Folds.General: instance Frames.Folds.General.EndoFieldFoldsToRecordFolds '[] record f
+ Frames.Folds.General: instance forall k1 k (c :: k -> GHC.Types.Constraint) (t :: (k1, k)). c (Data.Vinyl.TypeLevel.Snd t) => Frames.Folds.General.ConstrainedField c t
+ Frames.Folds.General: newtype FoldEndo f t
+ Frames.Folds.General: newtype FoldRecord record f g rs a
+ Frames.Folds.General: recFieldF :: forall t rs a record f. (KnownField t, Applicative f) => (forall x. f x -> Maybe x) -> Fold a (Snd t) -> (record (f :. ElField) rs -> f a) -> FoldRecord record f (f :. ElField) rs t
+ Frames.Folds.General: sequenceEndoFolds :: forall rs record f. (RApply rs, RPureConstrained KnownField rs, EndoFieldFoldsToRecordFolds rs record f, IsoRec rs record f, Functor f) => Rec (FoldEndo f) rs -> Fold (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.Folds.General: sequenceRecFold :: forall as rs record f. IsoRec rs record f => Rec (FoldRecord record f (f :. ElField) as) rs -> Fold (record (f :. ElField) as) (record (f :. ElField) rs)
+ Frames.Folds.General: type EndoFold a = Fold a a
+ Frames.Folds.Maybe: FoldEndo :: EndoFold (f (Snd t)) -> FoldEndo f t
+ Frames.Folds.Maybe: FoldRecord :: Fold (record (f :. ElField) rs) (g a) -> FoldRecord record f g rs a
+ Frames.Folds.Maybe: [unFoldEndo] :: FoldEndo f t -> EndoFold (f (Snd t))
+ Frames.Folds.Maybe: [unFoldRecord] :: FoldRecord record f g rs a -> Fold (record (f :. ElField) rs) (g a)
+ Frames.Folds.Maybe: fieldToFieldFold :: forall x y rs record. (KnownField x, KnownField y, ElemOf rs x, RecGetFieldC x record Maybe rs) => Fold (Snd x) (Snd y) -> FoldRecord record Maybe (Maybe :. ElField) rs y
+ Frames.Folds.Maybe: foldAll :: (RPureConstrained KnownField rs, RApply rs, EndoFieldFoldsToRecordFolds rs record Maybe, IsoRec rs record Maybe) => (forall a. Fold a a) -> Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
+ Frames.Folds.Maybe: foldAllConstrained :: forall c rs record. (RPureConstrained (ConstrainedField c) rs, RPureConstrained KnownField rs, RApply rs, EndoFieldFoldsToRecordFolds rs record Maybe, IsoRec rs record Maybe) => (forall a. c a => Fold a a) -> Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
+ Frames.Folds.Maybe: foldAllMonoid :: forall g rs record. (RPureConstrained (ConstrainedField (MonoidalField g)) rs, RPureConstrained KnownField rs, RApply rs, EndoFieldFoldsToRecordFolds rs record Maybe, IsoRec rs record Maybe) => Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
+ Frames.Folds.Maybe: maybeFoldAllConstrained :: forall c rs record. (RPureConstrained (ConstrainedField c) rs, RPureConstrained KnownField rs, RApply rs, EndoFieldFoldsToRecordFolds rs record Maybe, IsoRec rs record Maybe) => (forall a. c a => Fold (Maybe a) (Maybe a)) -> Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
+ Frames.Folds.Maybe: newtype FoldEndo f t
+ Frames.Folds.Maybe: newtype FoldRecord record f g rs a
+ Frames.Folds.Maybe: recFieldF :: forall t rs a record. KnownField t => Fold a (Snd t) -> (record (Maybe :. ElField) rs -> Maybe a) -> FoldRecord record Maybe (Maybe :. ElField) rs t
+ Frames.Folds.Maybe: sequenceEndoFolds :: forall rs record. (RApply rs, RPureConstrained KnownField rs, EndoFieldFoldsToRecordFolds rs record Maybe, IsoRec rs record Maybe) => Rec (FoldEndo Maybe) rs -> Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
+ Frames.Folds.Maybe: sequenceRecFold :: forall as rs record. IsoRec rs record Maybe => Rec (FoldRecord record Maybe (Maybe :. ElField) as) rs -> Fold (record (Maybe :. ElField) as) (record (Maybe :. ElField) rs)
+ Frames.Folds.Maybe: type EndoFold a = Fold a a
+ Frames.MapReduce.General: assignKeys :: forall ks rs record f. RCastC ks rs record f => Assign (record (f :. ElField) ks) (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.MapReduce.General: assignKeysAndData :: forall ks cs rs record f. (RCastC ks rs record f, RCastC cs rs record f) => Assign (record (f :. ElField) ks) (record (f :. ElField) rs) (record (f :. ElField) cs)
+ Frames.MapReduce.General: class IsoRec rs record f
+ Frames.MapReduce.General: class RCastC rs ss record f
+ Frames.MapReduce.General: class RecGetFieldC t record f rs
+ Frames.MapReduce.General: foldAndAddKey :: (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))
+ Frames.MapReduce.General: fromRec :: IsoRec rs record f => Rec (f :. ElField) rs -> record (f :. ElField) rs
+ Frames.MapReduce.General: instance (Data.Vinyl.Core.RPureConstrained (Data.Vinyl.SRec.FieldOffset (f Data.Vinyl.Functor.:. Data.Vinyl.Functor.ElField) ss) rs, Data.Vinyl.Core.RPureConstrained (Data.Vinyl.SRec.FieldOffset (f Data.Vinyl.Functor.:. Data.Vinyl.Functor.ElField) rs) rs, Data.Vinyl.Core.RFoldMap rs, Data.Vinyl.Core.RMap rs, Data.Vinyl.Core.RApply rs, Foreign.Storable.Storable (Data.Vinyl.Core.Rec (f Data.Vinyl.Functor.:. Data.Vinyl.Functor.ElField) rs)) => Frames.MapReduce.General.RCastC rs ss Data.Vinyl.SRec.SRec f
+ Frames.MapReduce.General: instance (Data.Vinyl.Derived.KnownField t, GHC.Base.Functor f, Frames.MapReduce.General.RecGetFieldC t record f (t : rs), Frames.MapReduce.General.RCastC rs (t : rs) record f, Data.Hashable.Class.Hashable (f (Data.Vinyl.TypeLevel.Snd t)), Data.Hashable.Class.Hashable (record (f Data.Vinyl.Functor.:. Data.Vinyl.Functor.ElField) rs)) => Data.Hashable.Class.Hashable (record (f Data.Vinyl.Functor.:. Data.Vinyl.Functor.ElField) (t : rs))
+ Frames.MapReduce.General: instance (Data.Vinyl.TypeLevel.IndexWitnesses (Data.Vinyl.TypeLevel.RImage rs ss), Data.Vinyl.TypeLevel.NatToInt (Data.Vinyl.TypeLevel.RLength rs)) => Frames.MapReduce.General.RCastC rs ss Data.Vinyl.ARec.ARec f
+ Frames.MapReduce.General: instance (Data.Vinyl.TypeLevel.NatToInt (Data.Vinyl.TypeLevel.RLength rs), Data.Vinyl.Core.RecApplicative rs, Data.Vinyl.Core.RPureConstrained (Data.Vinyl.ARec.IndexableField rs) rs) => Frames.MapReduce.General.IsoRec rs Data.Vinyl.ARec.ARec f
+ Frames.MapReduce.General: instance Data.Vinyl.Lens.RecSubset Data.Vinyl.Core.Rec rs ss (Data.Vinyl.TypeLevel.RImage rs ss) => Frames.MapReduce.General.RCastC rs ss Data.Vinyl.Core.Rec f
+ Frames.MapReduce.General: instance Data.Vinyl.SRec.FieldOffset (f Data.Vinyl.Functor.:. Data.Vinyl.Functor.ElField) rs t => Frames.MapReduce.General.RecGetFieldC t Data.Vinyl.SRec.SRec f rs
+ Frames.MapReduce.General: instance Foreign.Storable.Storable (Data.Vinyl.Core.Rec (f Data.Vinyl.Functor.:. Data.Vinyl.Functor.ElField) rs) => Frames.MapReduce.General.IsoRec rs Data.Vinyl.SRec.SRec f
+ Frames.MapReduce.General: instance Frames.MapReduce.General.IsoRec rs Data.Vinyl.Core.Rec f
+ Frames.MapReduce.General: instance Frames.MapReduce.General.RecGetFieldC t Data.Vinyl.ARec.ARec f rs
+ Frames.MapReduce.General: instance Frames.MapReduce.General.RecGetFieldC t Data.Vinyl.Core.Rec f rs
+ Frames.MapReduce.General: instance forall k (record :: ((GHC.Types.Symbol, *) -> *) -> [k] -> *) (f :: * -> *). Data.Hashable.Class.Hashable (record (f Data.Vinyl.Functor.:. Data.Vinyl.Functor.ElField) '[])
+ Frames.MapReduce.General: makeRecsWithKey :: (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)))
+ Frames.MapReduce.General: makeRecsWithKeyM :: (Monad m, Functor g, Foldable g, IsoRec ks record f, IsoRec as record f, IsoRec (ks ++ as) record f) => (y -> record (f :. ElField) as) -> ReduceM m (record (f :. ElField) ks) x (g y) -> ReduceM m (record (f :. ElField) ks) x (g (record (f :. ElField) (ks ++ as)))
+ Frames.MapReduce.General: rcastF :: RCastC rs ss record f => record (f :. ElField) ss -> record (f :. ElField) rs
+ Frames.MapReduce.General: reduceAndAddKey :: forall ks cs x record f. (IsoRec ks record f, IsoRec cs record f, IsoRec (ks ++ cs) record f) => (forall h. Foldable h => h x -> record (f :. ElField) cs) -> Reduce (record (f :. ElField) ks) x (record (f :. ElField) (ks ++ cs))
+ Frames.MapReduce.General: rgetF :: (RecGetFieldC t record f rs, KnownField t, ElemOf rs t) => record (f :. ElField) rs -> (f :. ElField) t
+ Frames.MapReduce.General: rgetFieldF :: (RecGetFieldC t record f rs, KnownField t, Functor f, ElemOf rs t) => record (f :. ElField) rs -> f (Snd t)
+ Frames.MapReduce.General: splitOnKeys :: forall ks rs cs record f. (RCastC ks rs record f, RCastC cs rs record f, cs ~ RDeleteAll ks rs) => Assign (record (f :. ElField) ks) (record (f :. ElField) rs) (record (f :. ElField) cs)
+ Frames.MapReduce.General: toRec :: IsoRec rs record f => record (f :. ElField) rs -> Rec (f :. ElField) rs
+ Frames.MapReduce.General: unpackFilterOnField :: forall t rs record f. (Functor f, KnownField t, ElemOf rs t, RecGetFieldC t record f rs) => (f (Snd t) -> Bool) -> Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.MapReduce.General: unpackFilterOnGoodField :: forall t rs record f. (Functor f, KnownField t, ElemOf rs t, RecGetFieldC t record f rs) => (forall a. f a -> Maybe a) -> (Snd t -> Bool) -> Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.MapReduce.General: unpackFilterRow :: (record (f :. ElField) rs -> Bool) -> Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.MapReduce.General: unpackGoodRows :: forall cs rs record f. RCastC cs rs record f => (record (f :. ElField) cs -> Bool) -> Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.MapReduce.General: unpackNoOp :: Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)
+ Frames.MapReduce.Maybe: assignKeys :: forall ks rs record. RCastC ks rs record Maybe => Assign (record (Maybe :. ElField) ks) (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
+ Frames.MapReduce.Maybe: assignKeysAndData :: forall ks cs rs record. (RCastC ks rs record Maybe, RCastC cs rs record Maybe) => Assign (record (Maybe :. ElField) ks) (record (Maybe :. ElField) rs) (record (Maybe :. ElField) cs)
+ Frames.MapReduce.Maybe: foldAndAddKey :: (IsoRec ks record Maybe, IsoRec cs record Maybe, IsoRec (ks ++ cs) record Maybe, RecVec (ks ++ cs)) => Fold x (record (Maybe :. ElField) cs) -> Reduce (record (Maybe :. ElField) ks) x (record (Maybe :. ElField) (ks ++ cs))
+ Frames.MapReduce.Maybe: makeRecsWithKey :: (Functor g, Foldable g, IsoRec ks record Maybe, IsoRec as record Maybe, IsoRec (ks ++ as) record Maybe, RecVec (ks ++ as)) => (y -> record (Maybe :. ElField) as) -> Reduce (record (Maybe :. ElField) ks) x (g y) -> Reduce (record (Maybe :. ElField) ks) x (g (record (Maybe :. ElField) (ks ++ as)))
+ Frames.MapReduce.Maybe: makeRecsWithKeyM :: (Monad m, Functor g, Foldable g, IsoRec ks record Maybe, IsoRec as record Maybe, IsoRec (ks ++ as) record Maybe, RecVec (ks ++ as)) => (y -> record (Maybe :. ElField) as) -> ReduceM m (record (Maybe :. ElField) ks) x (g y) -> ReduceM m (record (Maybe :. ElField) ks) x (g (record (Maybe :. ElField) (ks ++ as)))
+ Frames.MapReduce.Maybe: reduceAndAddKey :: forall ks cs x record. (IsoRec ks record Maybe, IsoRec cs record Maybe, IsoRec (ks ++ cs) record Maybe, RecVec (ks ++ cs)) => (forall h. Foldable h => h x -> record (Maybe :. ElField) cs) -> Reduce (record (Maybe :. ElField) ks) x (record (Maybe :. ElField) (ks ++ cs))
+ Frames.MapReduce.Maybe: splitOnKeys :: forall ks rs cs record. (RCastC ks rs record Maybe, RCastC cs rs record Maybe, cs ~ RDeleteAll ks rs) => Assign (record (Maybe :. ElField) ks) (record (Maybe :. ElField) rs) (record (Maybe :. ElField) cs)
+ Frames.MapReduce.Maybe: unpackFilterOnField :: forall t rs record. (KnownField t, ElemOf rs t, RecGetFieldC t record Maybe rs) => (Maybe (Snd t) -> Bool) -> Unpack (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
+ Frames.MapReduce.Maybe: unpackFilterRow :: (record (Maybe :. ElField) rs -> Bool) -> Unpack (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
+ Frames.MapReduce.Maybe: unpackGoodRecRows :: forall cs rs record. RCastC cs rs Rec Maybe => Unpack (Rec (Maybe :. ElField) rs) (Rec (Maybe :. ElField) rs)
+ Frames.MapReduce.Maybe: unpackGoodRows :: forall cs rs record. RCastC cs rs record Maybe => (record (Maybe :. ElField) cs -> Bool) -> Unpack (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)
+ Frames.MapReduce.Maybe: unpackNoOp :: Unpack (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)

Files

CHANGELOG.md view
@@ -1,3 +1,12 @@+v 0.2.0.0 +* Added Combinators for ```record (Maybe :. ElField) rs``` (Much thanks to Tim Pierson, @o1lo01ol1o, for the idea and the work!).+* Added Combinators polymorphic in record type (```Rec```, ```ARec``` or ```SRec``` are supported) and composed interpretation functor ```f :. ElField```+* ```Maybe :. ElField``` case now uses the general case in order to avoid code duplication+* ```Record``` case still uses separate code because the amount of new coercion code required was enough to not seem worth the re-use of the polymorphic case.++v 0.1.0.2 +* Changed example from "executable" to "test-suite".  Now it doens't need to be built and its dependencies don't leak to library users.+ v 0.1.0.1 * lowered containers lower bound * rasied some outdated upper bounds (profunctors, hashable)
Frames-map-reduce.cabal view
@@ -1,7 +1,7 @@ cabal-version:       2.2  name:                Frames-map-reduce-version:             0.1.0.1+version:             0.2.0.0 synopsis:            Frames wrapper for map-reduce-folds and some extra folds helpers. description:         Frames-map-reduce provides some helpers for using the map-reduce-folds library with vinyl records and Frames.                      These include functions for filtering Frames, splitting records into key columns and data columns and@@ -26,21 +26,26 @@ library   ghc-options: -Wall -funbox-strict-fields   exposed-modules: Frames.Folds+                 , Frames.Folds.Maybe+                 , Frames.Folds.General                  , Frames.MapReduce+                 , Frames.MapReduce.Maybe+                 , Frames.MapReduce.General    build-depends: Frames               >= 0.6.1 && < 0.7,                  base                 >= 4.12.0 && < 4.13,                  containers           >= 0.5.0 && < 0.7,                  hashable             >= 1.2.7 && < 1.4,                  map-reduce-folds     >= 0.1.0.0,                 -                 profunctors          >= 5.3 && < 5.5,+                 profunctors          >= 5.3 && < 5.6,                  vinyl                >= 0.11.0 && < 0.12,                  foldl                >= 1.4.5 && < 1.5,                  newtype              >= 0.2 && < 0.3   hs-source-dirs:      src   default-language:    Haskell2010 -executable AddRowsByLabel+test-suite AddRowsByLabel+    type: exitcode-stdio-1.0     main-is: AddRowsByLabel.hs     hs-source-dirs: examples     ghc-options: -Wall
examples/AddRowsByLabel.hs view
@@ -1,26 +1,33 @@-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE TypeOperators     #-} {-# LANGUAGE DataKinds         #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications  #-}+{-# LANGUAGE TypeOperators     #-}+{-# LANGUAGE InstanceSigs      #-} module Main where--import qualified Frames.MapReduce              as FMR-import qualified Frames.Folds                  as FF--import qualified Frames                        as F-import qualified Data.Vinyl                    as V+import qualified Control.Foldl                 as FL import qualified Data.List                     as L import qualified Data.Text                     as T-import qualified Control.Foldl                 as FL-import           Data.Monoid                    ( Sum )+import qualified Data.Vinyl                    as V+import           Data.Vinyl.Functor             ( Compose(..)+                                                , (:.)+                                                )+import qualified Frames                        as F+import qualified Frames.CSV                    as F+import qualified Frames.Folds                  as FF+import qualified Frames.Folds.Maybe            as FFM+import qualified Frames.MapReduce              as FMR+import qualified Frames.MapReduce.Maybe        as FMRM import           System.Random                  ( newStdGen                                                 , randomRs                                                 )+ -- Create types for the cols                                                 type Label = "label" F.:-> T.Text type Y = "y" F.:-> Double type X = "x" F.:-> Double-type AllCols = [Label,Y,X]+type AllCols = '[Label, Y, X]  -- filter, leaving only rows with labels 'A', 'B' or 'C' unpack = FMR.unpackFilterOnField @Label (`elem` ["A", "B", "C"])@@ -34,18 +41,55 @@ -- put it all together: filter, group by label, sum the data cols and re-attach the key. -- Then turn the resulting list of Frames (each with only one Record in this case) -- into one Frame via (<>).+ mrFold = FMR.concatFold $ FMR.mapReduceFold unpack assign reduce ++-- Bleh, this should go in Frames.  +instance (Eq (F.ElField a)) => Eq (Compose Maybe F.ElField a) where+  (==) (Compose fga) (Compose fga') = fga == fga'++instance (Ord (F.ElField a)) => Ord (Compose Maybe F.ElField a) where+  compare (Compose fga) (Compose fga') = fga `compare` fga'++unpack'+  :: FMR.Unpack (F.Rec (Maybe :. F.ElField) rs) (F.Rec (Maybe :. F.ElField) rs)+unpack' = FMRM.unpackNoOp++assign'+  :: FMR.Assign+       (F.Rec (Maybe :. F.ElField) '[Label])+       (F.Rec (Maybe :. F.ElField) '[Label, X, Y])+       (F.Rec (Maybe :. F.ElField) '[X, Y])+assign' = FMRM.splitOnKeys @'[Label]++reduce'+  :: FMR.Reduce+       (F.Rec (Maybe :. F.ElField) '[Label])+       (F.Rec (Maybe :. F.ElField) '[X, Y])+       (F.Rec (Maybe :. F.ElField) '[Label, X, Y])+reduce' = FMRM.foldAndAddKey $ (FFM.foldAllConstrained @Num @'[X, Y]) FL.sum++mrFold'+  :: FMR.Fold+       (F.Rec (Maybe :. F.ElField) '[Label, X, Y])+       [F.Rec (Maybe :. F.ElField) '[Label, X, Y]]+mrFold' = FMR.mapReduceFold unpack' assign' reduce'+ main :: IO () main = do   f <- createFrame 1000   let result = FMR.fold mrFold f   putStrLn $ (L.intercalate "\n" $ fmap show $ FL.fold FL.list result)+  let result' = FMR.fold mrFold' createHolyRows+  putStrLn . unlines . fmap show $ FL.fold FL.list result'  {- Output-{label :-> "A", y :-> 1293.6893073755323, x :-> 1386.4314446405742}-{label :-> "B", y :-> 1940.9402110282622, x :-> 2244.645291592506}-{label :-> "C", y :-> 2009.8541388288395, x :-> 2128.7190606123568}+{label :-> "A", y :-> 1577.3965303339942, x :-> 1507.286289962377}+{label :-> "B", y :-> 1934.223021597267, x :-> 2135.9312483902577}+{label :-> "C", y :-> 1528.6898777108415, x :-> 1810.5096765228654}+{Just label :-> "A", Just x :-> 5.0, Just y :-> 2.0}+{Just label :-> "Z", Just x :-> 5.0, Just y :-> 9.0} -}  --- create the Frame@@ -60,3 +104,14 @@           F.&: (randDbls !! (n + m))           F.&: V.RNil   return $ F.toFrame $ fmap oneRow [0 .. (n - 1)]++createHolyRows :: [F.Rec (Maybe F.:. F.ElField) '[Label, X, Y]]+createHolyRows = fmap go [one, two, three, four]+ where+  go =+    V.rmap (either (const (Compose Nothing)) (Compose . Just) . getCompose)+      . F.readRec+  one   = ["A", "1", "2"]+  two   = ["Z", "NaN", "3"]+  three = ["A", "4", "lol"]+  four  = ["Z", "5", "6"]
src/Frames/Folds.hs view
@@ -18,7 +18,7 @@ {-# LANGUAGE UndecidableSuperClasses #-} {-# OPTIONS_GHC -fwarn-incomplete-patterns #-} {-|-Module      : Frames.Folds+Module      : Frames.Monomorphic.Folds Description : Types and functions to simplify folding over Vinyl/Frames records. Leans heavily on the foldl package.  Copyright   : (c) Adam Conner-Sax 2019 License     : BSD@@ -34,10 +34,12 @@      -- ** Types to act as "interpretation functors" for records of folds   , FoldEndo(..)+  , FoldFieldEndo(..)   , FoldRecord(..)    -- * functions for building records of folds   , recFieldF+  , fieldToFieldFold    -- * functions for turning records of folds into folds of records   , sequenceRecFold@@ -47,6 +49,10 @@   , foldAll   , foldAllConstrained   , foldAllMonoid++  -- * for generalizing+  , monoidWrapperToFold+  , MonoidalField   ) where 
+ src/Frames/Folds/General.hs view
@@ -0,0 +1,277 @@+{-# LANGUAGE AllowAmbiguousTypes   #-}+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TemplateHaskell       #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-}+{-# LANGUAGE UndecidableSuperClasses #-}+{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}+{-|+Module      : Frames.Folds.General+Description : Types and functions to simplify folding over Vinyl/Frames records. Leans heavily on the foldl package. +Copyright   : (c) Adam Conner-Sax 2019+License     : BSD+Maintainer  : adam_conner_sax@yahoo.com+Stability   : experimental++Frames.Folds contains various helper functions designed to simplify folding over Frames/Vinyl records given some way of folding over each column.+-}+module Frames.Folds.General+  (+    -- * Types+    EndoFold++    -- ** Types to act as "interpretation functors" for records of folds+  , FoldEndo(..)+  , FoldRecord(..)++  -- * classes+  , EndoFieldFoldsToRecordFolds+  , ConstrainedField++  -- * functions for building records of folds+  , recFieldF+  , fieldToFieldFold++  -- * functions for turning records of folds into folds of records+  , sequenceRecFold+  , sequenceEndoFolds++  -- * functions using constraints to extend an endo-fold across a record+  , foldAll+  , foldAllConstrained+  , functorFoldAllConstrained+  , foldAllMonoid+  )+where++import           Frames.MapReduce.General       ( RecGetFieldC(..)+                                                , RCastC(..)+                                                , IsoRec(..)+                                                )+import           Frames.Folds                   ( EndoFold+                                                , FoldFieldEndo(..)+                                                , monoidWrapperToFold+                                                , MonoidalField+                                                )++import qualified Control.Foldl                 as FL++import qualified Data.Profunctor               as P+import qualified Data.Vinyl                    as V+import           Data.Vinyl                     ( ElField )+import qualified Data.Vinyl.TypeLevel          as V+import qualified Data.Vinyl.Functor            as V+import qualified Frames                        as F+import           Frames                         ( (:.) )+import qualified Frames.Melt                   as F+++-- | Turn and EndoFold (Maybe a) into an EndoFold ((Maybe :. ElField) '(s, a))+fieldFold+  :: (Functor f, V.KnownField t)+  => EndoFold (f (V.Snd t))+  -> EndoFold ((f :. ElField) t)+fieldFold =+  P.dimap (fmap (\(V.Field x) -> x) . V.getCompose) (V.Compose . fmap V.Field)+{-# INLINABLE fieldFold #-}++-- | Wrapper for Endo-folds of the field types of ElFields+newtype FoldEndo f t = FoldEndo { unFoldEndo :: EndoFold (f (V.Snd t)) }++-- | Wrapper for folds from a record to an interpreted field.  Usually g ~ ElField+newtype FoldRecord record f g rs a = FoldRecord { unFoldRecord :: FL.Fold (record (f :. ElField) rs) (g a) }++-- | Control.Foldl helper for filtering+filteredFold :: (f a -> Maybe a) -> FL.Fold a b -> FL.Fold (f a) b+filteredFold toMaybe (FL.Fold step begin done) = FL.Fold step' begin done+  where step' x = maybe x (step x) . toMaybe++-- | Helper for building a 'FoldRecord' from a given fold and function of the record+recFieldF+  :: forall t rs a record f+   . (V.KnownField t, Applicative f)+  => (forall x . f x -> Maybe x)+  -> FL.Fold a (V.Snd t) -- ^ A fold from some type a to the field type of an ElField+  -> (record (f :. ElField) rs -> f a)+  -> FoldRecord record f (f :. ElField) rs t -- ^ the resulting 'FoldRecord'-wrapped fold +recFieldF toMaybe fld fromRecF = FoldRecord+  $ P.dimap fromRecF (V.Compose . pure . V.Field) (filteredFold toMaybe fld)+{-# INLINABLE recFieldF #-}++-- | special case of 'recFieldF' for the case when the function from the record to the folded type+-- is just retrieving the value in a field.+fieldToFieldFold+  :: forall x y rs record f+   . ( V.KnownField x+     , V.KnownField y+     , F.ElemOf rs x+     , RecGetFieldC x record f rs+     , Applicative f+     )+  => (forall z . f z -> Maybe z)+  -> FL.Fold (V.Snd x) (V.Snd y) -- ^ the fold to be wrapped+  -> FoldRecord record f (f :. ElField) rs y -- ^ the wrapped fold+fieldToFieldFold toMaybe fld = recFieldF toMaybe fld (rgetFieldF @x)+{-# INLINABLE fieldToFieldFold #-}++-- | Expand a record of folds, each from the entire record to one field, into a record of folds each from a larger record to the smaller one.+expandFoldInRecord+  :: forall rs as record f+   . (RCastC as rs record f, V.RMap as)+  => V.Rec (FoldRecord record f (f :. ElField) as) as -- ^ original fold +  -> V.Rec (FoldRecord record f (f :. ElField) rs) as -- ^ resulting fold +expandFoldInRecord = V.rmap (FoldRecord . FL.premap rcastF . unFoldRecord)+{-# INLINABLE expandFoldInRecord #-}++-- | Change a record of single field folds to a record of folds from the entire record to each field+class EndoFieldFoldsToRecordFolds rs record f where+  endoFieldFoldsToRecordFolds :: F.Rec (FoldFieldEndo (f :. ElField)) rs -> F.Rec (FoldRecord record f (f :. ElField) rs) rs+++instance EndoFieldFoldsToRecordFolds '[] record f where+  endoFieldFoldsToRecordFolds _ = V.RNil+  {-# INLINABLE endoFieldFoldsToRecordFolds #-}++instance (EndoFieldFoldsToRecordFolds rs record f+         , RCastC rs (r ': rs) record f+         , V.KnownField r+         , RecGetFieldC r record f (r ': rs)+         , V.RMap rs+         ) => EndoFieldFoldsToRecordFolds (r ': rs) record f where+  endoFieldFoldsToRecordFolds (fe V.:& fes) = FoldRecord (FL.premap (rgetF @r) (unFoldFieldEndo fe)) V.:& expandFoldInRecord @(r ': rs) (endoFieldFoldsToRecordFolds fes)+  {-# INLINABLE endoFieldFoldsToRecordFolds #-}++-- can we do all/some of this via F.Rec (Fold as) bs?+-- | Turn a Record of folds into a fold over records+sequenceRecFold+  :: forall as rs record f+   . (IsoRec rs record f)+  => F.Rec (FoldRecord record f (f :. ElField) as) rs+  -> FL.Fold (record (f :. ElField) as) (record (f :. ElField) rs)+sequenceRecFold = fmap fromRec . V.rtraverse unFoldRecord+{-# INLINABLE sequenceRecFold #-}++-- | turn a record of folds over each field, into a fold over records +sequenceFieldEndoFolds+  :: (EndoFieldFoldsToRecordFolds rs record f, IsoRec rs record f)+  => F.Rec (FoldFieldEndo (f :. ElField)) rs+  -> FL.Fold (record (f :. ElField) rs) (record (f :. ElField) rs)+sequenceFieldEndoFolds = sequenceRecFold . endoFieldFoldsToRecordFolds+{-# INLINABLE sequenceFieldEndoFolds #-}++liftFold+  :: (V.KnownField t, Functor f)+  => FL.Fold (f (V.Snd t)) (f (V.Snd t))+  -> FoldFieldEndo (f :. ElField) t+liftFold = FoldFieldEndo . fieldFold+{-# INLINABLE liftFold #-}++-- This is not a natural transformation, FoldEndoT ~> FoldEndo F.EField, because of the constraint+liftFoldEndo+  :: (V.KnownField t, Functor f)+  => FoldEndo f t+  -> FoldFieldEndo (f :. ElField) t+liftFoldEndo = FoldFieldEndo . fieldFold . unFoldEndo+{-# INLINABLE liftFoldEndo #-}++liftFolds+  :: (V.RPureConstrained V.KnownField rs, V.RApply rs, Functor f)+  => F.Rec (FoldEndo f) rs+  -> F.Rec (FoldFieldEndo (f :. ElField)) rs+liftFolds = V.rapply liftedFs+  where liftedFs = V.rpureConstrained @V.KnownField $ V.Lift liftFoldEndo+{-# INLINABLE liftFolds #-}++-- | turn a record of endo-folds over each field, into a fold over records +sequenceEndoFolds+  :: forall rs record f+   . ( V.RApply rs+     , V.RPureConstrained V.KnownField rs+     , EndoFieldFoldsToRecordFolds rs record f+     , IsoRec rs record f+     , Functor f+     )+  => F.Rec (FoldEndo f) rs+  -> FL.Fold (record (f :. ElField) rs) (record (f :. ElField) rs)+sequenceEndoFolds = sequenceFieldEndoFolds . liftFolds+{-# INLINABLE sequenceEndoFolds #-}++-- | apply an unconstrained endo-fold, e.g., a fold which takes the last item in a container, to every field in a record+foldAll+  :: ( V.RPureConstrained V.KnownField rs+     , V.RApply rs+     , EndoFieldFoldsToRecordFolds rs record f+     , IsoRec rs record f+     , Functor f+     )+  => (forall a . FL.Fold a a)+  -> FL.Fold (record (f :. ElField) rs) (record (f :. ElField) rs)+foldAll f = sequenceEndoFolds $ V.rpureConstrained @V.KnownField (FoldEndo f)+{-# INLINABLE foldAll #-}++class (c  (V.Snd t)) => ConstrainedField c t+instance (c  (V.Snd t)) => ConstrainedField c t++-- | Apply a constrained endo-fold to all fields of a record.+-- May require a use of TypeApplications, e.g., foldAllConstrained @Num FL.sum+foldAllConstrained+  :: forall c rs record f+   . ( V.RPureConstrained (ConstrainedField c) rs+     , V.RPureConstrained V.KnownField rs+     , V.RApply rs+     , EndoFieldFoldsToRecordFolds rs record f+     , IsoRec rs record f+     , Applicative f+     )+  => (forall a . f a -> Maybe a)+  -> (forall a . c a => FL.Fold a a)+  -> FL.Fold (record (f :. ElField) rs) (record (f :. ElField) rs)+foldAllConstrained toMaybe f =+  sequenceEndoFolds $ V.rpureConstrained @(ConstrainedField c)+    (FoldEndo (fmap pure $ filteredFold toMaybe f))+{-# INLINABLE foldAllConstrained #-}++functorFoldAllConstrained+  :: forall c rs record f+   . ( V.RPureConstrained (ConstrainedField c) rs+     , V.RPureConstrained V.KnownField rs+     , V.RApply rs+     , EndoFieldFoldsToRecordFolds rs record f+     , IsoRec rs record f+     , Applicative f+     )+  => (forall a . c a => FL.Fold (f a) (f a))+  -> FL.Fold (record (f :. ElField) rs) (record (f :. ElField) rs)+functorFoldAllConstrained f =+  sequenceEndoFolds $ V.rpureConstrained @(ConstrainedField c) (FoldEndo f)+{-# INLINABLE functorFoldAllConstrained #-}++-- | Given a monoid-wrapper, e.g., Sum, apply the derived endo-fold to all fields of a record+-- This is strictly less powerful than foldAllConstrained but might be simpler to use in some cases+foldAllMonoid+  :: forall g rs record f+   . ( V.RPureConstrained (ConstrainedField (MonoidalField g)) rs+     , V.RPureConstrained V.KnownField rs+     , V.RApply rs+     , EndoFieldFoldsToRecordFolds rs record f+     , IsoRec rs record f+     , Applicative f+     )+  => (forall a . f a -> Maybe a)+  -> FL.Fold (record (f :. ElField) rs) (record (f :. ElField) rs)+foldAllMonoid toMaybe =+  foldAllConstrained @(MonoidalField g) toMaybe $ monoidWrapperToFold @g+{-# INLINABLE foldAllMonoid #-}+
+ src/Frames/Folds/Maybe.hs view
@@ -0,0 +1,177 @@+{-# LANGUAGE AllowAmbiguousTypes   #-}+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TemplateHaskell       #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-}+{-# LANGUAGE UndecidableSuperClasses #-}+{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}+{-|+Module      : Frames.Folds.Maybe+Description : Types and functions to simplify folding over Vinyl/Frames records. Leans heavily on the foldl package. +Copyright   : (c) Adam Conner-Sax 2019+License     : BSD+Maintainer  : adam_conner_sax@yahoo.com+Stability   : experimental++Frames.Folds contains various helper functions designed to simplify folding over Frames/Vinyl records given some way of folding over each column.+-}+module Frames.Folds.Maybe+  (+    -- * Types+    EndoFold++    -- ** Types to act as "interpretation functors" for records of folds+  , FoldEndo(..)+  , FoldRecord(..)++  -- * functions for building records of folds+  , recFieldF+  , fieldToFieldFold++  -- * functions for turning records of folds into folds of records+  , sequenceRecFold+  , sequenceEndoFolds++  -- * functions using constraints to extend an endo-fold across a record+  , foldAll+  , foldAllConstrained+  , maybeFoldAllConstrained+  , foldAllMonoid+  )+where++import qualified Frames.MapReduce.General      as MG+import qualified Frames.Folds.General          as FG+import           Frames.Folds.General           ( FoldEndo(..)+                                                , FoldRecord(..)+                                                )++import           Frames.Folds                   ( EndoFold+                                                , FoldFieldEndo(..)+                                                , monoidWrapperToFold+                                                , MonoidalField+                                                )++import qualified Control.Foldl                 as FL++import qualified Data.Profunctor               as P+import qualified Data.Vinyl                    as V+import           Data.Vinyl                     ( ElField )+import qualified Data.Vinyl.TypeLevel          as V+import qualified Data.Vinyl.Functor            as V+import qualified Frames                        as F+import           Frames                         ( (:.) )+import qualified Frames.Melt                   as F++-- | Helper for building a 'FoldRecord' from a given fold and function of the record+recFieldF+  :: forall t rs a record+   . V.KnownField t+  => FL.Fold a (V.Snd t) -- ^ A fold from some type a to the field type of an ElField +  -> (record (Maybe :. ElField) rs -> Maybe a) -- ^ a function to get the a value from the input record+  -> FG.FoldRecord record Maybe (Maybe :. ElField) rs t -- ^ the resulting 'FoldRecord'-wrapped fold +recFieldF = FG.recFieldF id+{-# INLINABLE recFieldF #-}++-- | special case of 'recFieldF' for the case when the function from the record to the folded type+-- is just retrieving the value in a field.+fieldToFieldFold+  :: forall x y rs record+   . ( V.KnownField x+     , V.KnownField y+     , F.ElemOf rs x+     , MG.RecGetFieldC x record Maybe rs+     )+  => FL.Fold (V.Snd x) (V.Snd y) -- ^ the fold to be wrapped+  -> FG.FoldRecord record Maybe (Maybe :. ElField) rs y -- ^ the wrapped fold+fieldToFieldFold = FG.fieldToFieldFold @x id+{-# INLINABLE fieldToFieldFold #-}++-- can we do all/some of this via F.Rec (Fold as) bs?+-- | Turn a Record of folds into a fold over records+sequenceRecFold+  :: forall as rs record+   . (MG.IsoRec rs record Maybe)+  => F.Rec (FG.FoldRecord record Maybe (Maybe :. ElField) as) rs+  -> FL.Fold (record (Maybe :. ElField) as) (record (Maybe :. ElField) rs)+sequenceRecFold = FG.sequenceRecFold --V.rtraverse unFoldRecord+{-# INLINABLE sequenceRecFold #-}++-- | turn a record of endo-folds over each field, into a fold over records +sequenceEndoFolds+  :: forall rs record+   . ( V.RApply rs+     , V.RPureConstrained V.KnownField rs+     , FG.EndoFieldFoldsToRecordFolds rs record Maybe+     , MG.IsoRec rs record Maybe+     )+  => F.Rec (FG.FoldEndo Maybe) rs+  -> FL.Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)+sequenceEndoFolds = FG.sequenceEndoFolds --sequenceFieldEndoFolds . liftFolds+{-# INLINABLE sequenceEndoFolds #-}++-- | apply an unconstrained endo-fold, e.g., a fold which takes the last item in a container, to every field in a record+foldAll+  :: ( V.RPureConstrained V.KnownField rs+     , V.RApply rs+     , FG.EndoFieldFoldsToRecordFolds rs record Maybe+     , MG.IsoRec rs record Maybe+     )+  => (forall a . FL.Fold a a)+  -> FL.Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)+foldAll = FG.foldAll+{-# INLINABLE foldAll #-}++-- | Apply a constrained endo-fold to all fields of a record.+-- May require a use of TypeApplications, e.g., foldAllConstrained @Num FL.sum+foldAllConstrained+  :: forall c rs record+   . ( V.RPureConstrained (FG.ConstrainedField c) rs+     , V.RPureConstrained V.KnownField rs+     , V.RApply rs+     , FG.EndoFieldFoldsToRecordFolds rs record Maybe+     , MG.IsoRec rs record Maybe+     )+  => (forall a . c a => FL.Fold a a)+  -> FL.Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)+foldAllConstrained = FG.foldAllConstrained @c id+{-# INLINABLE foldAllConstrained #-}++maybeFoldAllConstrained+  :: forall c rs record+   . ( V.RPureConstrained (FG.ConstrainedField c) rs+     , V.RPureConstrained V.KnownField rs+     , V.RApply rs+     , FG.EndoFieldFoldsToRecordFolds rs record Maybe+     , MG.IsoRec rs record Maybe+     )+  => (forall a . c a => FL.Fold (Maybe a) (Maybe a))+  -> FL.Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)+maybeFoldAllConstrained = FG.functorFoldAllConstrained @c+{-# INLINABLE maybeFoldAllConstrained #-}++-- | Given a monoid-wrapper, e.g., Sum, apply the derived endo-fold to all fields of a record+-- This is strictly less powerful than foldAllConstrained but might be simpler to use in some cases+foldAllMonoid+  :: forall g rs record+   . ( V.RPureConstrained (FG.ConstrainedField (MonoidalField g)) rs+     , V.RPureConstrained V.KnownField rs+     , V.RApply rs+     , FG.EndoFieldFoldsToRecordFolds rs record Maybe+     , MG.IsoRec rs record Maybe+     )+  => FL.Fold (record (Maybe :. ElField) rs) (record (Maybe :. ElField) rs)+foldAllMonoid = FG.foldAllMonoid @g id+{-# INLINABLE foldAllMonoid #-}
src/Frames/MapReduce.hs view
@@ -18,8 +18,8 @@ {-# LANGUAGE InstanceSigs          #-} {-# OPTIONS_GHC -fwarn-incomplete-patterns #-} {-|-Module      : Frames.MapReduce-Description : Helpers for using the map-reduce-folds package with Frames+Module      : Frames.Monomorphic.MapReduce+Description : Helpers for using the map-reduce-folds package with Frames.  Monomorphic in record and interpretation functor. Copyright   : (c) Adam Conner-Sax 2019 License     : BSD-3-Clause Maintainer  : adam_conner_sax@yahoo.com@@ -68,6 +68,8 @@ import qualified Frames.InCore                 as FI import qualified Data.Vinyl                    as V import qualified Data.Vinyl.TypeLevel          as V+import qualified Data.Vinyl.Functor            as V+import           Data.Coerce                    ( coerce )  -- | This is only here so we can use hash maps for the grouping step.  This should properly be in Frames itself. instance Hash.Hashable (F.Record '[]) where
+ src/Frames/MapReduce/General.hs view
@@ -0,0 +1,258 @@+{-# 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.General where++import qualified Control.MapReduce             as MR+import           Control.MapReduce                 -- for re-export++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           Data.Kind                      ( Type )+import           GHC.TypeLits                   ( Symbol )++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+import qualified Data.Vinyl.SRec               as V+import qualified Data.Vinyl.ARec               as V+import qualified Foreign.Storable              as FS++class RecGetFieldC t record f rs where+  rgetF ::  ( V.KnownField t+            , F.ElemOf rs t+            ) => record (f :. ElField) rs -> (f :. ElField) t+  rgetFieldF :: ( V.KnownField t+                , Functor f+                , F.ElemOf rs t+                ) => record (f :. ElField) rs -> f (V.Snd t)+  rgetFieldF = fmap V.getField . V.getCompose . rgetF @t @record @f @rs++instance RecGetFieldC t V.Rec f rs where+  rgetF = V.rget @t++instance RecGetFieldC t V.ARec f rs where+  rgetF = V.aget @t++instance (V.FieldOffset (f :. ElField) rs t) => RecGetFieldC t V.SRec f rs where+  rgetF = V.sget @_ @t . V.getSRecNT --srecGetField @t @f @rs++class RCastC rs ss record f  where+  rcastF :: record (f :. ElField) ss -> record (f :. ElField) rs++instance V.RecSubset V.Rec rs ss (V.RImage rs ss) => RCastC rs ss V.Rec f where+  rcastF = V.rcast++instance (V.IndexWitnesses (V.RImage rs ss), V.NatToInt (V.RLength rs)) => RCastC rs ss V.ARec f where+  rcastF = V.arecGetSubset++instance (V.RPureConstrained (V.FieldOffset (f :. ElField) ss) rs+         , V.RPureConstrained (V.FieldOffset (f :. ElField) rs) rs+         , V.RFoldMap rs+         , V.RMap rs+         , V.RApply rs+         , FS.Storable (V.Rec (f :. ElField) rs)) =>  RCastC rs ss V.SRec f where+  rcastF = V.SRecNT . V.srecGetSubset . V.getSRecNT++class IsoRec rs record f where+  toRec :: record (f :. ElField) rs -> V.Rec (f :. ElField) rs+  fromRec :: V.Rec (f :. ElField) rs -> record (f :. ElField) rs++instance IsoRec rs V.Rec f where+  toRec = id+  fromRec = id++instance FS.Storable (V.Rec (f :. ElField) rs) => IsoRec rs V.SRec f where+  toRec = V.fromSRec+  fromRec = V.toSRec+++instance (V.NatToInt (V.RLength rs)+         , V.RecApplicative rs+         , V.RPureConstrained (V.IndexableField rs) rs) => IsoRec rs V.ARec f where+  toRec = V.fromARec+  fromRec = V.toARec++-- | This is only here so we can use hash maps for the grouping step.  This should properly be in Frames itself.+instance Hash.Hashable (record (f :. ElField)  '[]) where+  hash = const 0+  {-# INLINABLE hash #-}+  hashWithSalt s = const s -- TODO: this seems BAD! Or not?+  {-# INLINABLE hashWithSalt #-}++instance (V.KnownField t+         , Functor f+         , RecGetFieldC t record f (t ': rs)+         , RCastC rs (t ': rs) record f+         , Hash.Hashable (f (V.Snd t))+         , Hash.Hashable (record (f :. ElField) rs)+         ) => Hash.Hashable (record (f :. ElField) (t ': rs)) where+  hashWithSalt s r = s `Hash.hashWithSalt` (rgetFieldF @t r) `Hash.hashWithSalt` (rcastF @rs r)+  {-# INLINABLE hashWithSalt #-}++-- | Don't do anything +unpackNoOp :: MR.Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)+unpackNoOp = MR.Filter (const True)++-- | Filter records using a function on the entire record. +unpackFilterRow+  :: (record (f :. ElField) rs -> Bool)+  -> MR.Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)+unpackFilterRow test = MR.Filter test++-- | 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 f+   . (Functor f, V.KnownField t, F.ElemOf rs t, RecGetFieldC t record f rs)+  => (f (V.Snd t) -> Bool)+  -> MR.Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)+unpackFilterOnField test = unpackFilterRow (test . rgetFieldF @t)++unpackFilterOnGoodField+  :: forall t rs record f+   . (Functor f, V.KnownField t, F.ElemOf rs t, RecGetFieldC t record f rs)+  => (forall a . f a -> Maybe a)+  -> (V.Snd t -> Bool)+  -> MR.Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)+unpackFilterOnGoodField toMaybe testValue =+  let test' = (maybe False testValue) . toMaybe in unpackFilterOnField @t test'++-- | An unpack step which specifies a subset of columns, cs,+-- (via a type-application) and then filters a @record (Maybe :. Elfield) rs@+-- to only rows which have all good data in that subset.+unpackGoodRows+  :: forall cs rs record f+   . (RCastC cs rs record f)+  => (record (f :. ElField) cs -> Bool)+  -> MR.Unpack (record (f :. ElField) rs) (record (f :. ElField) rs)+unpackGoodRows testSubset = unpackFilterRow (testSubset . rcastF @cs)++-- | 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 f+   . (RCastC ks rs record f, RCastC cs rs record f)+  => MR.Assign+       (record (f :. ElField) ks)+       (record (f :. ElField) rs)+       (record (f :. ElField) cs)+assignKeysAndData = MR.assign (rcastF @ks) (rcastF @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 f+   . (RCastC ks rs record f, RCastC cs rs record f, cs ~ F.RDeleteAll ks rs)+  => MR.Assign+       (record (f :. ElField) ks)+       (record (f :. ElField) rs)+       (record (f :. 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 f+   . (RCastC ks rs record f)+  => MR.Assign+       (record (f :. ElField) ks)+       (record (f :. ElField) rs)+       (record (f :. ElField) rs)+assignKeys = MR.assign (rcastF @ks) id+{-# INLINABLE assignKeys #-}++-- | Reduce the data to a single row and then re-attach the key.+-- | NB: for all but Rec case, this will have to convert record to Rec and back for the append+reduceAndAddKey+  :: forall ks cs x record f+   . (IsoRec ks record f, IsoRec cs record f, IsoRec (ks V.++ cs) record f)+  => (forall h . Foldable h => h x -> record (f :. ElField) cs) -- ^ reduction step+  -> MR.Reduce+       (record (f :. ElField) ks)+       x+       (record (f :. ElField) (ks V.++ cs))+reduceAndAddKey process =+  MR.processAndLabel process (\k y -> fromRec (toRec k `V.rappend` toRec y))+{-# INLINABLE reduceAndAddKey #-}++-- | Reduce by folding the data to a single row and then re-attaching the key.+foldAndAddKey+  :: (IsoRec ks record f, IsoRec cs record f, IsoRec (ks V.++ cs) record f)+  => FL.Fold x (record (f :. ElField) cs) -- ^ reduction fold+  -> MR.Reduce+       (record (f :. ElField) ks)+       x+       (record (f :. ElField) (ks V.++ cs))+foldAndAddKey fld =+  MR.foldAndLabel fld (\k y -> fromRec (toRec k `V.rappend` toRec y))+{-# 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+     , IsoRec ks record f+     , IsoRec as record f+     , IsoRec (ks V.++ as) record f+     )+  => (y -> record (f :. ElField) as) -- ^ map a result to a record+  -> MR.Reduce (record (f :. ElField) ks) x (g y) -- ^ original reduce+  -> MR.Reduce+       (record (f :. ElField) ks)+       x+       (g (record (f :. ElField) (ks V.++ as)))+makeRecsWithKey makeRec reduceToY = MR.reduceMapWithKey addKey reduceToY+ where+  addKey k = fmap (\y -> fromRec . V.rappend (toRec k) . toRec $ makeRec y)+{-# 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+     , IsoRec ks record f+     , IsoRec as record f+     , IsoRec (ks V.++ as) record f+     )+  => (y -> record (f :. ElField) as) -- ^ map a result to a record+  -> MR.ReduceM m (record (f :. ElField) ks) x (g y) -- ^ original reduce+  -> MR.ReduceM+       m+       (record (f :. ElField) ks)+       x+       (g (record (f :. ElField) (ks V.++ as)))+makeRecsWithKeyM makeRec reduceToY = MR.reduceMMapWithKey addKey reduceToY+ where+  addKey k = fmap (\y -> fromRec . V.rappend (toRec k) . toRec $ makeRec y)+{-# INLINABLE makeRecsWithKeyM #-}++
+ src/Frames/MapReduce/Maybe.hs view
@@ -0,0 +1,191 @@+{-# 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 #-}