packages feed

Frames 0.7.0 → 0.7.1

raw patch · 6 files changed

+88/−15 lines, 6 filesdep ~basedep ~ghc-primPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base, ghc-prim

API changes (from Hackage documentation)

- Frames: data Rec (a :: u -> Type) (b :: [u]) :: forall u. () => u -> Type -> [u] -> Type
- Frames.ColumnUniverse: data CoRec (a :: k -> Type) (b :: [k]) :: forall k. () => k -> Type -> [k] -> Type
- Frames.ExtraInstances: instance forall a (f :: a -> *) (r :: a) (rs :: [a]). (Control.DeepSeq.NFData (f r), Control.DeepSeq.NFData (Data.Vinyl.Core.Rec f rs)) => Control.DeepSeq.NFData (Data.Vinyl.Core.Rec f (r : rs))
- Frames.ExtraInstances: instance forall k l (f :: l -> *) (g :: k -> l) (a :: k). Control.DeepSeq.NFData (f (g a)) => Control.DeepSeq.NFData (Data.Vinyl.Functor.Compose f g a)
+ Frames: data Rec (a :: u -> Type) (b :: [u])
+ Frames.ColumnUniverse: data CoRec (a :: k -> Type) (b :: [k])
+ Frames.Exploration: dropRows :: Int -> Frame (Record rs) -> Frame (Record rs)
+ Frames.Exploration: printFrame :: forall rs. (ColumnHeaders rs, RecMapMethod Show ElField rs, RecordToList rs) => String -> Frame (Record rs) -> IO ()
+ Frames.Exploration: showFrame :: forall rs. (ColumnHeaders rs, RecMapMethod Show ElField rs, RecordToList rs) => String -> Frame (Record rs) -> String
+ Frames.Exploration: takeRows :: Int -> Frame (Record rs) -> Frame (Record rs)
+ Frames.ExtraInstances: instance forall l k (f :: l -> *) (g :: k -> l) (a :: k). Control.DeepSeq.NFData (f (g a)) => Control.DeepSeq.NFData (Data.Vinyl.Functor.Compose f g a)
- Frames: (<+>) :: () => Rec f as -> Rec f bs -> Rec f (as ++ bs)
+ Frames: (<+>) :: forall k (f :: k -> Type) (as :: [k]) (bs :: [k]). Rec f as -> Rec f bs -> Rec f (as ++ bs)
- Frames: melt :: forall vs ts ss proxy. (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, HasLength vs, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> FrameRec ts -> FrameRec (ss ++ '["value" :-> CoRec ElField vs])
+ Frames: melt :: forall vs ts ss proxy. (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, HasLength vs, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> FrameRec ts -> FrameRec (ss ++ '["value" :-> CoRec ElField vs])
- Frames: meltRow :: (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> Record ts -> [Record (ss ++ '["value" :-> CoRec ElField vs])]
+ Frames: meltRow :: (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> Record ts -> [Record (ss ++ '["value" :-> CoRec ElField vs])]
- Frames: onCoRec :: RPureConstrained c ts => (forall (a :: k2). (a ∈ ts, c a) => f a -> g b) -> CoRec f ts -> g b
+ Frames: onCoRec :: forall k1 k2 c f (ts :: [k1]) (b :: k2) g. RPureConstrained c ts => (forall (a :: k1). (a ∈ ts, c a) => f a -> g b) -> CoRec f ts -> g b
- Frames: onField :: RPureConstrained c ts => (forall a. (a ∈ ts, c a) => a -> b) -> Field ts -> b
+ Frames: onField :: forall c (ts :: [Type]) b. RPureConstrained c ts => (forall a. (a ∈ ts, c a) => a -> b) -> Field ts -> b
- Frames: rcast :: (RecSubset record rs ss is, RecSubsetFCtx record f) => record f ss -> record f rs
+ Frames: rcast :: forall k1 k2 (rs :: [k1]) (ss :: [k1]) (f :: k2 -> Type) record (is :: [Nat]). (RecSubset record rs ss is, RecSubsetFCtx record f) => record f ss -> record f rs
- Frames: rfield :: Functor f => (a -> f b) -> ElField ((,) s a) -> f (ElField ((,) s b))
+ Frames: rfield :: forall f a b (s :: Symbol). Functor f => (a -> f b) -> ElField '(s, a) -> f (ElField '(s, b))
- Frames: rsubset :: (RecSubset record rs ss is, Functor g, RecSubsetFCtx record f) => (record f rs -> g (record f rs)) -> record f ss -> g (record f ss)
+ Frames: rsubset :: forall k1 k2 (rs :: [k2]) (ss :: [k2]) (f :: k1 -> Type) g record (is :: [Nat]). (RecSubset record rs ss is, Functor g, RecSubsetFCtx record f) => (record f rs -> g (record f rs)) -> record f ss -> g (record f ss)
- Frames: runSafeP :: (MonadMask m, MonadIO m) => Effect (SafeT m) r -> Effect' m r
+ Frames: runSafeP :: forall (m :: Type -> Type) r. (MonadMask m, MonadIO m) => Effect (SafeT m) r -> Effect' m r
- Frames.Categorical: Categorical :: Set Text -> Categorical
+ Frames.Categorical: Categorical :: Set Text -> Categorical (n :: Nat)
- Frames.Categorical: [categories] :: Categorical -> Set Text
+ Frames.Categorical: [categories] :: Categorical (n :: Nat) -> Set Text
- Frames.Melt: melt :: forall vs ts ss proxy. (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, HasLength vs, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> FrameRec ts -> FrameRec (ss ++ '["value" :-> CoRec ElField vs])
+ Frames.Melt: melt :: forall vs ts ss proxy. (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, HasLength vs, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> FrameRec ts -> FrameRec (ss ++ '["value" :-> CoRec ElField vs])
- Frames.Melt: meltAux :: forall vs ss ts. (vs ⊆ ts, ss ⊆ ts, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => Record ts -> [Record (("value" :-> CoRec ElField vs) : ss)]
+ Frames.Melt: meltAux :: forall vs ss ts. (vs ⊆ ts, ss ⊆ ts, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => Record ts -> [Record (("value" :-> CoRec ElField vs) : ss)]
- Frames.Melt: meltRow :: (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> Record ts -> [Record (ss ++ '["value" :-> CoRec ElField vs])]
+ Frames.Melt: meltRow :: (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> Record ts -> [Record (ss ++ '["value" :-> CoRec ElField vs])]
- Frames.Melt: meltRow' :: forall proxy vs ts ss. (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> Record ts -> [Record (("value" :-> CoRec ElField vs) : ss)]
+ Frames.Melt: meltRow' :: forall proxy vs ts ss. (vs ⊆ ts, ss ⊆ ts, vs ~ RDeleteAll ss ts, Disjoint ss ts ~ 'True, ts ≅ (vs ++ ss), ColumnHeaders vs, RowToColumn vs vs) => proxy ss -> Record ts -> [Record (("value" :-> CoRec ElField vs) : ss)]
- Frames.RecF: rappend :: () => Rec f as -> Rec f bs -> Rec f (as ++ bs)
+ Frames.RecF: rappend :: forall k (f :: k -> Type) (as :: [k]) (bs :: [k]). Rec f as -> Rec f bs -> Rec f (as ++ bs)
- Frames.RecF: rtraverse :: Applicative h => (forall (x :: u). () => f x -> h (g x)) -> Rec f rs -> h (Rec g rs)
+ Frames.RecF: rtraverse :: forall u h f g (rs :: [u]). Applicative h => (forall (x :: u). () => f x -> h (g x)) -> Rec f rs -> h (Rec g rs)
- Frames.RecF: stripNames' :: (StripFieldNames ts, Functor f) => Rec (f :. ElField) ts -> Rec f (Unlabeled ts)
+ Frames.RecF: stripNames' :: forall (f :: Type -> Type). (StripFieldNames ts, Functor f) => Rec (f :. ElField) ts -> Rec f (Unlabeled ts)
- Frames.RecF: withNames' :: (StripFieldNames ts, Functor f) => Rec f (Unlabeled ts) -> Rec (f :. ElField) ts
+ Frames.RecF: withNames' :: forall (f :: Type -> Type). (StripFieldNames ts, Functor f) => Rec f (Unlabeled ts) -> Rec (f :. ElField) ts
- Frames.TH: RowGen :: [String] -> String -> Separator -> String -> Proxy a -> (Separator -> Producer [Text] (SafeT IO) ()) -> RowGen
+ Frames.TH: RowGen :: [String] -> String -> Separator -> String -> Proxy a -> (Separator -> Producer [Text] (SafeT IO) ()) -> RowGen (a :: [Type])
- Frames.TH: [columnNames] :: RowGen -> [String]
+ Frames.TH: [columnNames] :: RowGen (a :: [Type]) -> [String]
- Frames.TH: [columnUniverse] :: RowGen -> Proxy a
+ Frames.TH: [columnUniverse] :: RowGen (a :: [Type]) -> Proxy a
- Frames.TH: [lineReader] :: RowGen -> Separator -> Producer [Text] (SafeT IO) ()
+ Frames.TH: [lineReader] :: RowGen (a :: [Type]) -> Separator -> Producer [Text] (SafeT IO) ()
- Frames.TH: [rowTypeName] :: RowGen -> String
+ Frames.TH: [rowTypeName] :: RowGen (a :: [Type]) -> String
- Frames.TH: [separator] :: RowGen -> Separator
+ Frames.TH: [separator] :: RowGen (a :: [Type]) -> Separator
- Frames.TH: [tablePrefix] :: RowGen -> String
+ Frames.TH: [tablePrefix] :: RowGen (a :: [Type]) -> String

Files

CHANGELOG.md view
@@ -1,3 +1,9 @@+# 0.7.1++- Add `showFrame`, `printFrame`, `takeRows`, and `dropRows` to the `Frames.Exploration` module. These helpers for working with `Frames` are re-exported from the `Frames` module itself. Thanks to @chfin.++- GHC-9.0.1 support.+ # 0.7.0  GHC-8.10 support in Vinyl requires a major version bump.
Frames.cabal view
@@ -1,5 +1,5 @@ name:                Frames-version:             0.7.0+version:             0.7.1 synopsis:            Data frames For working with tabular data files description:         User-friendly, type safe, runtime efficient tooling for                      working with tabular data deserialized from@@ -30,7 +30,7 @@                      data/left1.csv data/right1.csv data/left_summary.csv                      data/FL2.csv cabal-version:       >=1.10-tested-with:         GHC == 8.4.4 || == 8.6.5 || == 8.8.3 || == 8.10.1+tested-with:         GHC == 8.4.4 || == 8.6.5 || == 8.8.4 || == 8.10.4 || == 9.0.1  source-repository head   type:     git@@ -64,8 +64,8 @@                        TypeOperators, ConstraintKinds, StandaloneDeriving,                        UndecidableInstances, ScopedTypeVariables,                        OverloadedStrings, TypeApplications-  build-depends:       base >=4.10 && <4.15,-                       ghc-prim >=0.3 && <0.7,+  build-depends:       base >=4.10 && <4.16,+                       ghc-prim >=0.3 && <0.8,                        primitive >= 0.6 && < 0.8,                        text >= 1.1.1.0,                        template-haskell,
src/Frames/CSV.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE CPP, DataKinds, DeriveLift, FlexibleContexts, FlexibleInstances, GADTs,              LambdaCase, OverloadedStrings, RankNTypes,              ScopedTypeVariables, TemplateHaskell, TypeApplications,@@ -68,7 +69,11 @@           hs' = [|map T.pack $(listE $  map (stringE . T.unpack) hs)|]           quoting' = lift quoting #if MIN_VERSION_template_haskell(2,16,0)+#if MIN_VERSION_template_haskell(2,17,0)+  liftTyped = liftCode . unsafeTExpCoerce . lift+#else   liftTyped = unsafeTExpCoerce . lift+#endif #endif  -- | Default 'ParseOptions' get column names from a header line, and
src/Frames/Exploration.hs view
@@ -10,8 +10,11 @@ -- | Functions useful for interactively exploring and experimenting -- with a data set. module Frames.Exploration (pipePreview, select, lenses, recToList,-                           pr, pr1) where+                           pr, pr1, showFrame, printFrame,+                           takeRows, dropRows) where import Data.Char (isSpace, isUpper)+import qualified Data.Foldable as F+import Data.List (intercalate) import Data.Proxy import qualified Data.Vinyl as V import qualified Data.Vinyl.Class.Method as V@@ -21,8 +24,11 @@ import Language.Haskell.TH import Language.Haskell.TH.Quote import Pipes hiding (Proxy)+import qualified Pipes as P import qualified Pipes.Prelude as P import Pipes.Safe (SafeT, runSafeT, MonadMask)+import Frames.Frame (Frame(Frame))+import Frames.RecF (columnHeaders, ColumnHeaders)  -- * Preview Results @@ -90,7 +96,7 @@              (V.RecMapMethod ((~) a) ElField rs, V.RecordToList rs)           => Record rs -> [a] recToList = V.recordToList . V.rmapMethod @((~) a) aux-  where aux :: a ~ (V.PayloadType ElField t)  => V.ElField t -> Const a t+  where aux :: a ~ V.PayloadType ElField t  => V.ElField t -> Const a t         aux (Field x) = Const x  -- * Helpers@@ -107,3 +113,34 @@ -- | Remove white space from both ends of a 'String'. strip :: String -> String strip = takeWhile (not . isSpace) . dropWhile isSpace++-- | @takeRows n frame@ produces a new 'Frame' made up of the first+-- @n@ rows of @frame@.+takeRows :: Int -> Frame (Record rs) -> Frame (Record rs)+takeRows n (Frame len rows) = Frame (min n len) rows++-- | @dropRows n frame@ produces a new 'Frame' just like @frame@, but+-- not including its first @n@ rows.+dropRows :: Int -> Frame (Record rs) -> Frame (Record rs)+dropRows n (Frame len rows) = Frame (max 0 (len - n)) (\i -> rows (i + n))++-- | Format a 'Frame' to a 'String'.+showFrame :: forall rs.+  (ColumnHeaders rs, V.RecMapMethod Show ElField rs, V.RecordToList rs)+  => String -- ^ Separator between fields+  -> Frame (Record rs) -- ^ The 'Frame' to be formatted to a 'String'+  -> String+showFrame sep frame =+  unlines (intercalate sep (columnHeaders (Proxy :: Proxy (Record rs))) : rows)+  where rows = P.toList (F.mapM_ (P.yield . intercalate sep . showFields) frame)++-- | Print a 'Frame' to 'System.IO.stdout'.+printFrame :: forall rs.+  (ColumnHeaders rs, V.RecMapMethod Show ElField rs, V.RecordToList rs)+  => String -- ^ Separator between fields+  -> Frame (Record rs) -- ^ The 'Frame' to be printed to @stdout@+  -> IO ()+printFrame sep frame = do+  putStrLn (intercalate sep (columnHeaders (Proxy :: Proxy (Record rs))))+  P.runEffect (rows >-> P.stdoutLn)+  where rows = F.mapM_ (P.yield . intercalate sep . showFields) frame
src/Frames/ExtraInstances.hs view
@@ -49,8 +49,11 @@ instance NFData1 VF.Identity where   liftRnf r = r . getIdentity +#if MIN_VERSION_vinyl(0,13,1)+#else instance (NFData (f r), NFData (Rec f rs)) => NFData (Rec f (r ': rs)) where   rnf (x :& xs) = rnf x `seq` rnf xs+#endif  instance NFData (Rec f '[]) where   rnf RNil = ()
test/Spec.hs view
@@ -10,7 +10,7 @@ import Data.List (find, isPrefixOf) import Data.Monoid (First(..)) import qualified Data.Text as T-import Language.Haskell.TH as TH+import qualified Language.Haskell.TH as TH import Language.Haskell.TH.Syntax (addDependentFile) import Frames import Frames.CSV (produceCSV)@@ -25,7 +25,7 @@ import Test.HUnit.Lang (assertFailure)  import qualified LatinTest as Latin-import qualified Issue114 as Issue114+import qualified Issue114 import qualified Issue145 import qualified NoHeader import qualified Categorical@@ -33,15 +33,16 @@ import qualified UncurryFold import qualified UncurryFoldNoHeader import qualified UncurryFoldPartialData+import Data.Vinyl (xrec)  -- | Extract all example @(CSV, generatedCode)@ pairs from -- @test/examples.toml@ csvTests :: [(CsvExample, String)] csvTests = $(do addDependentFile "test/examples.toml"                 csvExamples <- TH.runIO (examplesFrom "test/examples.toml")-                ListE <$> mapM (\x@(CsvExample _ c _) ->-                                  [e|(x,$(generateCode "Row" c))|])-                               csvExamples)+                TH.ListE <$> mapM (\x@(CsvExample _ c _) ->+                                     [e|(x,$(generateCode "Row" c))|])+                                  csvExamples)  -- | Detect type-compatible re-used names and do not attempt to -- re-generate definitions for them. This does not do the right thing@@ -67,7 +68,7 @@ -- -- Note that to load this file into a REPL may require some fiddling -- with the path to the examples file in the 'csvTests' splice above.-manualGeneration :: String -> Q Exp+manualGeneration :: String -> TH.Q TH.Exp manualGeneration k = do csvExamples <- TH.runIO (examplesFrom "test/examples.toml")                         maybe (error ("Table " ++ k ++ " not found"))                               (generateCode "Row")@@ -106,10 +107,10 @@ main = do   hspec $     do-#if __GLASGOW_HASKELL__ >= 804+        describe "Haskell type generation" $          mapM_ (\(CsvExample k _ g, g') -> it k (Code g' `shouldBe` Code g)) csvTests-#endif+        -- describe "Multiple tables" $        --    do _g <- H.runIO $        --             generatedFrom "test/examples.toml" "managers_employees"@@ -144,7 +145,7 @@            unless (frame == frame2)                   (assertFailure "Reparsed CSV differs from input")        describe "Latin1 Text Encoding" $-         do managers <- H.runIO (Latin.managers)+         do managers <- H.runIO Latin.managers             it "Parses" $               managers `shouldBe` ["João", "Esperança"]        describe "Skip Missing Data" $ do@@ -225,3 +226,24 @@          streamedChunks <- H.runIO Chunks.chunkStream          it "Can split an input stream into Frame chunks" $            streamedChunks `shouldBe` everyTenthEducation+       describe "Printing with take and drop" $ do+         let frame :: Frame (Record '[ "id" :-> Int, "manager" :-> Text+                                     , "age" :-> Int, "pay" :-> Double ])+             frame = toFrame [ xrec (1, "Joe", 53, 80000)+                             , xrec (2, "Sarah", 44, 80000) ]+         it "Can format a Frame to a String" $+           showFrame "\t" frame `shouldBe`+           unlines [+              "id\tmanager\tage\tpay"+            , "1\t\"Joe\"\t53\t80000.0"+            , "2\t\"Sarah\"\t44\t80000.0" ]+         it "Can take the first row" $+           showFrame "\t" (takeRows 1 frame) `shouldBe`+           unlines [+              "id\tmanager\tage\tpay"+            , "1\t\"Joe\"\t53\t80000.0" ]+         it "Can drop the first row" $+           showFrame "\t" (dropRows 1 frame) `shouldBe`+           unlines [+              "id\tmanager\tage\tpay"+            , "2\t\"Sarah\"\t44\t80000.0" ]