Hello community, here is the log from the commit of package ghc-Frames for openSUSE:Factory checked in at 2017-03-12 20:00:23 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ghc-Frames (Old) and /work/SRC/openSUSE:Factory/.ghc-Frames.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "ghc-Frames" Sun Mar 12 20:00:23 2017 rev:2 rq:476812 version:0.1.9 Changes: -------- --- /work/SRC/openSUSE:Factory/ghc-Frames/ghc-Frames.changes 2017-03-03 17:43:28.278149144 +0100 +++ /work/SRC/openSUSE:Factory/.ghc-Frames.new/ghc-Frames.changes 2017-03-12 20:00:24.160298287 +0100 @@ -1,0 +2,15 @@ +Mon Dec 19 10:18:57 UTC 2016 - psimons@suse.com + +- Update to version 0.1.9 with cabal2obs. + +------------------------------------------------------------------- +Sun Dec 4 19:47:52 UTC 2016 - psimons@suse.com + +- Update to version 0.1.8 with cabal2obs. + +------------------------------------------------------------------- +Thu Sep 15 06:39:23 UTC 2016 - psimons@suse.com + +- Update to version 0.1.6 revision 0 with cabal2obs. + +------------------------------------------------------------------- Old: ---- Frames-0.1.4.tar.gz New: ---- Frames-0.1.9.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ghc-Frames.spec ++++++ --- /var/tmp/diff_new_pack.2rbaSZ/_old 2017-03-12 20:00:24.724218494 +0100 +++ /var/tmp/diff_new_pack.2rbaSZ/_new 2017-03-12 20:00:24.728217928 +0100 @@ -1,7 +1,7 @@ # # spec file for package ghc-Frames # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,16 +17,16 @@ %global pkg_name Frames +%bcond_with tests Name: ghc-%{pkg_name} -Version: 0.1.4 +Version: 0.1.9 Release: 0 Summary: Data frames For working with tabular data files License: BSD-3-Clause -Group: System/Libraries +Group: Development/Languages/Other Url: https://hackage.haskell.org/package/%{pkg_name} Source0: https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz BuildRequires: ghc-Cabal-devel -# Begin cabal-rpm deps: BuildRequires: ghc-pipes-devel BuildRequires: ghc-primitive-devel BuildRequires: ghc-readable-devel @@ -37,7 +37,15 @@ BuildRequires: ghc-vector-devel BuildRequires: ghc-vinyl-devel BuildRoot: %{_tmppath}/%{name}-%{version}-build -# End cabal-rpm deps +%if %{with tests} +BuildRequires: ghc-directory-devel +BuildRequires: ghc-hspec-devel +BuildRequires: ghc-htoml-devel +BuildRequires: ghc-pretty-devel +BuildRequires: ghc-regex-applicative-devel +BuildRequires: ghc-temporary-devel +BuildRequires: ghc-unordered-containers-devel +%endif %description User-friendly, type safe, runtime efficient tooling for working with tabular @@ -59,14 +67,14 @@ %prep %setup -q -n %{pkg_name}-%{version} - %build %ghc_lib_build - %install %ghc_lib_install +%check +%cabal_test %post devel %ghc_pkg_recache ++++++ Frames-0.1.4.tar.gz -> Frames-0.1.9.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/CHANGELOG.md new/Frames-0.1.9/CHANGELOG.md --- old/Frames-0.1.4/CHANGELOG.md 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/CHANGELOG.md 2016-12-15 19:49:04.000000000 +0100 @@ -1,3 +1,14 @@ +# 0.1.9 + +Fixed column type inference bug that led the inferencer to prefer `Bool` too strongly. + +This was fallout from typing columns whose values are all 0 or 1 as `Bool`. + +# 0.1.6 + +Re-export `Frames.CSV.declareColumn` from `Frames`. This makes it much +easier to manually define column types. + # 0.1.4 Use `microlens` instead of `lens-family-core` for demos. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/Frames.cabal new/Frames-0.1.9/Frames.cabal --- old/Frames-0.1.4/Frames.cabal 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/Frames.cabal 2016-12-15 19:49:10.000000000 +0100 @@ -1,5 +1,5 @@ name: Frames -version: 0.1.4 +version: 0.1.9 synopsis: Data frames For working with tabular data files description: User-friendly, type safe, runtime efficient tooling for working with tabular data deserialized from @@ -17,6 +17,8 @@ extra-source-files: benchmarks/*.hs benchmarks/*.py demo/Main.hs CHANGELOG.md data/GetData.hs + test/examples.toml + test/data/managers.csv test/data/employees.csv cabal-version: >=1.10 tested-with: GHC == 7.10.3, GHC == 8.0.1 @@ -48,7 +50,7 @@ TypeOperators, ConstraintKinds, StandaloneDeriving, UndecidableInstances, ScopedTypeVariables, OverloadedStrings - build-depends: base >=4.7 && <4.10, + build-depends: base >=4.8 && <4.10, ghc-prim >=0.3 && <0.6, primitive >= 0.6 && < 0.7, text >= 1.1.1.0, @@ -68,7 +70,7 @@ buildable: False main-is: GetData.hs if flag(demos) - build-depends: base, bytestring, http-client, zip-archive + build-depends: base, bytestring, http-client >= 0.4.3, zip-archive, directory hs-source-dirs: data default-language: Haskell2010 ghc-options: -Wall @@ -82,9 +84,9 @@ build-depends: base, Frames, microlens, vector, text, template-haskell, - pipes >= 4.1.5 && < 4.3, - Chart >= 1.5 && < 1.8, - Chart-diagrams >= 1.5 && < 1.8, + pipes >= 4.1.5 && < 4.4, + Chart >= 1.5 && < 1.9, + Chart-diagrams >= 1.5 && < 1.9, diagrams-rasterific >= 1.3 && < 1.4, diagrams-lib >= 1.3 && < 1.4, readable, containers, statistics @@ -98,9 +100,9 @@ if flag(demos) build-depends: base, Frames, microlens, vector, text, template-haskell, - pipes >= 4.1.5 && < 4.3, - Chart >= 1.5 && < 1.8, - Chart-diagrams >= 1.5 && < 1.8, + pipes >= 4.1.5 && < 4.4, + Chart >= 1.5 && < 1.9, + Chart-diagrams >= 1.5 && < 1.9, diagrams-rasterific >= 1.3 && < 1.4, diagrams-lib >= 1.3 && < 1.4, readable, containers, statistics @@ -115,10 +117,11 @@ if flag(demos) build-depends: base, list-t, microlens, transformers, Frames, vector, text, template-haskell, ghc-prim, readable, - pipes >= 4.1.5 && < 4.3 + pipes >= 4.1.5 && < 4.4 hs-source-dirs: demo default-language: Haskell2010 - ghc-options: -O2 -fllvm + ghc-options: -O2 + -- ghc-options: -O2 -fllvm executable tutorial if !flag(demos) @@ -128,7 +131,7 @@ build-depends: base, Frames, microlens, vector, text, template-haskell, readable, foldl >= 1.1.0 && < 1.3, - pipes >= 4.1.5 && < 4.3 + pipes >= 4.1.5 && < 4.4 hs-source-dirs: demo default-language: Haskell2010 @@ -140,10 +143,13 @@ if flag(demos) build-depends: base, Frames, foldl >= 1.1.0 && < 1.3, - pipes >= 4.1.5 && < 4.3 + pipes >= 4.1.5 && < 4.4 hs-source-dirs: benchmarks default-language: Haskell2010 - ghc-options: -O2 -fllvm + -- ghc-options: -O2 + + -- Use opt and llc found on PATH rather than the GHC settings file + ghc-options: -O2 -pgmlo opt -pgmlc llc -fllvm -- A demonstration of dealing with missing data. Provided for source -- code and experimentation rather than a useful executable. @@ -152,7 +158,7 @@ buildable: False main-is: MissingData.hs if flag(demos) - build-depends: base, Frames, vinyl + build-depends: base, Frames, vinyl, pipes hs-source-dirs: demo default-language: Haskell2010 @@ -162,7 +168,7 @@ hs-source-dirs: benchmarks main-is: InsuranceBench.hs build-depends: base, criterion, Frames, transformers, - pipes >= 4.1.5 && < 4.3 + pipes >= 4.1.5 && < 4.4 ghc-options: -O2 default-language: Haskell2010 @@ -175,3 +181,21 @@ build-depends: base, Frames, vinyl, text, readable hs-source-dirs: demo default-language: Haskell2010 + +test-suite spec + type: exitcode-stdio-1.0 + hs-source-dirs: test + main-is: Spec.hs + other-modules: DataCSV PrettyTH Temp + build-depends: base, text, hspec, Frames, template-haskell, + temporary, directory, htoml, regex-applicative, pretty, + unordered-containers + ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall + default-language: Haskell2010 + +test-suite overlap + type: exitcode-stdio-1.0 + hs-source-dirs: test + main-is: Overlap.hs + build-depends: base, Frames + default-language: Haskell2010 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/benchmarks/BenchDemo.hs new/Frames-0.1.9/benchmarks/BenchDemo.hs --- old/Frames-0.1.4/benchmarks/BenchDemo.hs 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/benchmarks/BenchDemo.hs 2016-08-19 19:14:49.000000000 +0200 @@ -2,9 +2,8 @@ -- | Demonstration of streaming data processing. Try building with -- cabal (@cabal build benchdemo@), then running in bash with -- something like, --- +-- -- @$ /usr/bin/time -l dist/build/benchdemo/benchdemo 2>&1 | head -n 4@ -import Control.Applicative import qualified Control.Foldl as F import Frames import Pipes.Prelude (fold) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/data/GetData.hs new/Frames-0.1.9/data/GetData.hs --- old/Frames-0.1.4/data/GetData.hs 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/data/GetData.hs 2016-08-19 18:34:47.000000000 +0200 @@ -3,38 +3,40 @@ import qualified Data.ByteString.Lazy.Char8 as B import Data.Maybe (fromJust) import Network.HTTP.Client +import System.Directory (createDirectoryIfMissing) getPrestige :: IO () -getPrestige = withManager defaultManagerSettings $ \m -> - httpLbs req m >>= - B.writeFile "data/prestige.csv" . responseBody - where Just req = parseUrl "http://vincentarelbundock.github.io/Rdatasets/csv/car/Prestige.csv" +getPrestige = do m <- newManager defaultManagerSettings + httpLbs req m >>= + B.writeFile "data/prestige.csv" . responseBody + where Just req = parseUrlThrow "http://vincentarelbundock.github.io/Rdatasets/csv/car/Prestige.csv" getFLinsurance :: IO () -getFLinsurance = withManager defaultManagerSettings $ \m -> - httpLbs req m >>= - B.writeFile "data/FL2.csv" - . B.map fixup . fromEntry . fromJust - . findEntryByPath "FL_insurance_sample.csv" - . toArchive - . responseBody +getFLinsurance = do m <- newManager defaultManagerSettings + httpLbs req m >>= + B.writeFile "data/FL2.csv" + . B.map fixup . fromEntry . fromJust + . findEntryByPath "FL_insurance_sample.csv" + . toArchive + . responseBody where fixup '\r' = '\n' fixup c = c - Just req = parseUrl "http://spatialkeydocs.s3.amazonaws.com/FL_insurance_sample.csv.zip" + Just req = parseUrlThrow "http://spatialkeydocs.s3.amazonaws.com/FL_insurance_sample.csv.zip" getAdultIncome :: IO () -getAdultIncome = withManager defaultManagerSettings $ \m -> - httpLbs req m >>= - B.writeFile "data/adult.csv" - . B.append colNames - . responseBody - where Just req = parseUrl "http://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data" +getAdultIncome = do m <- newManager defaultManagerSettings + httpLbs req m >>= + B.writeFile "data/adult.csv" + . B.append colNames + . responseBody + where Just req = parseUrlThrow "http://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data" colNames = "age, workclass, fnlwgt, education, education-num, \ \marital-status, occupation, relationship, race, sex, \ \capital-gain, capital-loss, hours-per-week, \ \native-country\n" main :: IO () -main = do getPrestige +main = do createDirectoryIfMissing False "data" + getPrestige getFLinsurance getAdultIncome diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/demo/MissingData.hs new/Frames-0.1.9/demo/MissingData.hs --- old/Frames-0.1.4/demo/MissingData.hs 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/demo/MissingData.hs 2016-12-15 07:41:25.000000000 +0100 @@ -1,11 +1,14 @@ -{-# LANGUAGE DataKinds, FlexibleInstances, QuasiQuotes, TypeOperators, - UndecidableInstances #-} +{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, + MultiParamTypeClasses, QuasiQuotes, TemplateHaskell, + TypeOperators, UndecidableInstances #-} -- | An example of dealing with rows that contain missing data. We may -- want to fill in the gaps with default values. import Data.Monoid ((<>), First(..)) import Data.Vinyl (Rec(..), rmap, RecApplicative, rapply) import Data.Vinyl.Functor (Lift(..)) import Frames hiding ((:&)) +import Pipes (cat, Producer, (>->)) +import Pipes.Prelude as P -- An en passant Default class class Default a where @@ -43,5 +46,26 @@ unholy :: Maybe (Record '[MyString, MyInt, MyBool]) unholy = recMaybe . rmap getFirst $ rapply (rmap (Lift . flip (<>)) def) holyRow +-- * Reading a CSV file with missing data + +instance Default ("col_a" :-> Int) where def = Col 0 +instance Default ("col_b" :-> Text) where def = Col mempty + +tableTypes "Row" "data/missing.csv" + +-- | Fill in missing columns with a default 'Row' value synthesized +-- from 'Default' instances. +holesFilled :: Producer Row IO () +holesFilled = readTableMaybe "data/missing.csv" >-> P.map (fromJust . holeFiller) + where holeFiller :: Rec Maybe (RecordColumns Row) -> Maybe Row + holeFiller = recMaybe + . rmap getFirst + . rapply (rmap (Lift . flip (<>)) def) + . rmap First + fromJust = maybe (error "Frames holesFilled failure") id + +showFilledHoles :: IO () +showFilledHoles = pipePreview holesFilled 10 cat + main :: IO () main = return () diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/demo/Plot.hs new/Frames-0.1.9/demo/Plot.hs --- old/Frames-0.1.4/demo/Plot.hs 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/demo/Plot.hs 2016-07-12 17:55:35.000000000 +0200 @@ -1,4 +1,5 @@ {-# LANGUAGE DataKinds, FlexibleContexts, TemplateHaskell #-} +module Main where import qualified Data.Vector.Unboxed as V import Diagrams.Backend.Rasterific import Diagrams (dims2D, width, height) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/src/Frames/CSV.hs new/Frames-0.1.9/src/Frames/CSV.hs --- old/Frames-0.1.4/src/Frames/CSV.hs 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/src/Frames/CSV.hs 2016-12-13 18:36:01.000000000 +0100 @@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns, + CPP, DataKinds, FlexibleInstances, KindSignatures, @@ -15,18 +16,22 @@ -- necessary types so that you can write type safe programs referring -- to those types. module Frames.CSV where +#if __GLASGOW_HASKELL__ < 710 import Control.Applicative ((<$>), pure, (<*>)) -import Control.Arrow (first) +import Data.Foldable (foldMap) +import Data.Traversable (sequenceA) +import Data.Monoid (Monoid) +#endif + +import Control.Arrow (first, second) import Control.Monad (MonadPlus(..), when, void) import Control.Monad.IO.Class import Data.Char (isAlpha, isAlphaNum, toLower, toUpper) -import Data.Foldable (foldMap) -import Data.Maybe (fromMaybe, isNothing) -import Data.Monoid ((<>), Monoid(..)) +import Data.Maybe (isNothing, fromMaybe) +import Data.Monoid ((<>)) import Data.Proxy import qualified Data.Text as T import qualified Data.Text.IO as T -import Data.Traversable (sequenceA) import Data.Vinyl (RElem, Rec) import Data.Vinyl.TypeLevel (RIndex) import Frames.Col @@ -240,11 +245,11 @@ -- * Template Haskell -- | Generate a column type. -recDec :: ColumnTypeable a => [(T.Text, a)] -> Q Type +recDec :: [(T.Text, Q Type)] -> Q Type recDec = appT [t|Record|] . go where go [] = return PromotedNilT go ((n,t):cs) = - [t|($(litT $ strTyLit (T.unpack n)) :-> $(colType t)) ': $(go cs) |] + [t|($(litT $ strTyLit (T.unpack n)) :-> $(t)) ': $(go cs) |] -- | Massage a column name from a CSV file into a valid Haskell type -- identifier. @@ -266,7 +271,8 @@ mkColTDec :: TypeQ -> Name -> DecQ mkColTDec colTypeQ colTName = tySynD colTName [] colTypeQ --- | Declare a singleton value of the given column type. +-- | Declare a singleton value of the given column type and lenses for +-- working with that column. mkColPDec :: Name -> TypeQ -> T.Text -> DecsQ mkColPDec colTName colTy colPName = sequenceA [tySig, val, tySig', val'] where nm = mkName $ T.unpack colPName @@ -291,15 +297,17 @@ (normalB [e|rlens' (Proxy :: Proxy $(conT colTName))|]) [] +lowerHead :: T.Text -> Maybe T.Text +lowerHead = fmap aux . T.uncons + where aux (c,t) = T.cons (toLower c) t + -- | For each column, we declare a type synonym for its type, and a -- Proxy value of that type. colDec :: ColumnTypeable a => T.Text -> T.Text -> a -> DecsQ colDec prefix colName colTy = (:) <$> mkColTDec colTypeQ colTName' <*> mkColPDec colTName' colTyQ colPName where colTName = sanitizeTypeName (prefix <> colName) - colPName = maybe "colDec impossible" - (\(c,t) -> T.cons (toLower c) t) - (T.uncons colTName) + colPName = fromMaybe "colDec impossible" (lowerHead colTName) colTName' = mkName $ T.unpack colTName colTyQ = colType colTy colTypeQ = [t|$(litT . strTyLit $ T.unpack colName) :-> $colTyQ|] @@ -376,7 +384,7 @@ tableType' (RowGen {..}) csvFile = pure . TySynD (mkName rowTypeName) [] <$> (runIO (readColHeaders opts csvFile) >>= recDec') - where recDec' = recDec :: [(T.Text, a)] -> Q Type + where recDec' = recDec . map (second colType) :: [(T.Text, a)] -> Q Type colNames' | null columnNames = Nothing | otherwise = Just (map T.pack columnNames) opts = ParserOptions colNames' separator (RFC4180Quoting '\"') @@ -399,7 +407,7 @@ optsDec <- valD (varP optsName) (normalB $ lift opts) [] colDecs <- concat <$> mapM (uncurry $ colDec (T.pack tablePrefix)) headers return (recTy : optsTy : optsDec : colDecs) - where recDec' = recDec :: [(T.Text, a)] -> Q Type + where recDec' = recDec . map (second colType) :: [(T.Text, a)] -> Q Type colNames' | null columnNames = Nothing | otherwise = Just (map T.pack columnNames) opts = ParserOptions colNames' separator (RFC4180Quoting '\"') @@ -419,11 +427,17 @@ h:t -> mkName $ toLower h : t ++ "Parser" optsTy <- sigD optsName [t|ParserOptions|] optsDec <- valD (varP optsName) (normalB $ lift opts) [] - colDecs <- concat <$> mapM (uncurry $ colDec (T.pack tablePrefix)) headers + colDecs <- concat <$> mapM (uncurry mkColDecs) headers return (recTy : optsTy : optsDec : colDecs) -- (:) <$> (tySynD (mkName n) [] (recDec' headers)) -- <*> (concat <$> mapM (uncurry $ colDec (T.pack prefix)) headers) - where recDec' = recDec :: [(T.Text, a)] -> Q Type + where recDec' = recDec . map (second colType) :: [(T.Text, a)] -> Q Type colNames' | null columnNames = Nothing | otherwise = Just (map T.pack columnNames) opts = ParserOptions colNames' separator (RFC4180Quoting '\"') + mkColDecs colNm colTy = do + let safeName = tablePrefix ++ (T.unpack . sanitizeTypeName $ colNm) + mColNm <- lookupTypeName safeName + case mColNm of + Just _ -> pure [] + Nothing -> colDec (T.pack tablePrefix) colNm colTy diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/src/Frames/CoRec.hs new/Frames-0.1.9/src/Frames/CoRec.hs --- old/Frames-0.1.4/src/Frames/CoRec.hs 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/src/Frames/CoRec.hs 2016-12-10 01:30:46.000000000 +0100 @@ -38,6 +38,9 @@ data CoRec :: (* -> *) -> [*] -> * where Col :: RElem a ts (RIndex a ts) => !(f a) -> CoRec f ts +foldCoRec :: (forall a. RElem a ts (RIndex a ts) => f a -> b) -> CoRec f ts -> b +foldCoRec f (Col x) = f x + -- | A Field of a 'Record' is a 'CoRec Identity'. type Field = CoRec Identity @@ -73,7 +76,6 @@ zipRecsWith _ RNil _ = RNil zipRecsWith f (r :& rs) (s :& ss) = f r s :& zipRecsWith f rs ss - -- | Remove a 'Dict' wrapper from a value. dictId :: Dict c a -> Identity a dictId (Dict x) = Identity x diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/src/Frames/ColumnTypeable.hs new/Frames-0.1.9/src/Frames/ColumnTypeable.hs --- old/Frames-0.1.4/src/Frames/ColumnTypeable.hs 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/src/Frames/ColumnTypeable.hs 2016-09-15 17:15:53.000000000 +0200 @@ -38,6 +38,8 @@ instance Parseable Int where instance Parseable Float where instance Parseable Double where + -- Some CSV's export Doubles in a format like '1,000.00', filtering out commas lets us parse those sucessfully + parse = fmap Definitely . fromText . T.filter (/= ',') instance Parseable T.Text where -- | This class relates a universe of possible column types to Haskell diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/src/Frames/ColumnUniverse.hs new/Frames-0.1.9/src/Frames/ColumnUniverse.hs --- old/Frames-0.1.4/src/Frames/ColumnUniverse.hs 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/src/Frames/ColumnUniverse.hs 2016-12-13 19:18:56.000000000 +0100 @@ -18,7 +18,8 @@ TypeOperators, UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -module Frames.ColumnUniverse (CoRec, Columns, ColumnUniverse, CommonColumns) where +module Frames.ColumnUniverse (CoRec, Columns, ColumnUniverse, CommonColumns, + parsedTypeRep) where import Language.Haskell.TH #if __GLASGOW_HASKELL__ < 800 import Data.Monoid @@ -88,9 +89,22 @@ -- types. newtype ColInfo a = ColInfo (Q Type, Parsed (Typed a)) +parsedTypeRep :: ColInfo a -> Parsed TypeRep +parsedTypeRep (ColInfo (_,p)) = fmap getConst p + -- | We use a join semi-lattice on types for representations. The -- bottom of the lattice is effectively an error (we have nothing to -- represent), @Bool < Int@, @Int < Double@, and @forall n. n <= Text@. +-- +-- The high-level goal here is that we will pick the "greater" of two +-- choices in 'bestRep'. A 'Definitely' parse result is preferred over +-- a 'Possibly' parse result. If we have two distinct 'Possibly' parse +-- results, we give up. If we have two distinct 'Definitely' parse +-- results, we are in dangerous waters: all data is parseable at +-- /both/ types, so which do we default to? The defaulting choices +-- made here are described in the previous paragraph. If there is no +-- defaulting rule, we give up (i.e. use 'T.Text' as a +-- representation). lubTypeReps :: Parsed TypeRep -> Parsed TypeRep -> Maybe Ordering lubTypeReps (Possibly _) (Definitely _) = Just LT lubTypeReps (Definitely _) (Possibly _) = Just GT @@ -99,10 +113,12 @@ | otherwise = Nothing lubTypeReps (Definitely trX) (Definitely trY) | trX == trY = Just EQ - | trX == trInt && trY == trDbl = Just LT - | trX == trDbl && trY == trInt = Just GT + | trX == trInt && trY == trDbl = Just LT + | trX == trDbl && trY == trInt = Just GT | trX == trBool && trY == trInt = Just LT - | trX == trInt && trY == trBool = Just GT + | trX == trInt && trY == trBool = Just GT + | trX == trBool && trY == trDbl = Just LT + | trX == trDbl && trY == trBool = Just GT | otherwise = Nothing where trInt = typeRep (Proxy :: Proxy Int) trDbl = typeRep (Proxy :: Proxy Double) @@ -118,16 +134,26 @@ Nothing -> mempty -- | Find the best (i.e. smallest) 'CoRec' variant to represent a --- parsed value. +-- parsed value. For inspection in GHCi after loading this module, +-- consider this example: +-- +-- >>> :set -XTypeApplications +-- >>> :set -XOverloadedStrings +-- >>> import Frames.CoRec (foldCoRec) +-- >>> foldCoRec parsedTypeRep (bestRep @CommonColumns "2.3") +-- Definitely Double bestRep :: forall ts. (LAll Parseable ts, LAll Typeable ts, FoldRec ts ts, RecApplicative ts, T.Text ∈ ts) => T.Text -> CoRec ColInfo ts -bestRep = aux - . fromMaybe (Col (Compose $ Possibly (mkTyped :: Typed T.Text))) - . firstField - . elementTypes - . (tryParseAll :: T.Text -> Rec (Maybe :. (Parsed :. Proxy)) ts) +bestRep t + | T.null t = aux (Col (Compose (Possibly (mkTyped :: Typed T.Text)))) + | otherwise = aux + . fromMaybe (Col (Compose $ Possibly (mkTyped :: Typed T.Text))) + . firstField + . elementTypes + . (tryParseAll :: T.Text -> Rec (Maybe :. (Parsed :. Proxy)) ts) + $ t where aux :: CoRec (Parsed :. Typed) ts -> CoRec ColInfo ts aux (Col (Compose d@(Possibly (Const tr)))) = Col (ColInfo (quoteType tr, d)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/src/Frames.hs new/Frames-0.1.9/src/Frames.hs --- old/Frames-0.1.4/src/Frames.hs 2016-06-05 02:16:51.000000000 +0200 +++ new/Frames-0.1.9/src/Frames.hs 2016-08-23 18:56:17.000000000 +0200 @@ -25,7 +25,7 @@ import Frames.Col ((:->)(..)) import Frames.ColumnUniverse import Frames.CoRec (Field, onField, onCoRec) -import Frames.CSV (readTable, readTableMaybe, readTable', +import Frames.CSV (readTable, readTableMaybe, readTable', declareColumn, tableType, tableTypes, tableType', tableTypes') import Frames.Exploration import Frames.Frame diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/test/DataCSV.hs new/Frames-0.1.9/test/DataCSV.hs --- old/Frames-0.1.4/test/DataCSV.hs 1970-01-01 01:00:00.000000000 +0100 +++ new/Frames-0.1.9/test/DataCSV.hs 2016-12-06 06:50:45.000000000 +0100 @@ -0,0 +1,57 @@ +{-# LANGUAGE OverloadedStrings, TemplateHaskell #-} +module DataCSV where +import Control.Monad ((>=>)) +import Data.Bifunctor (first) +import qualified Data.HashMap.Lazy as H +import Data.Maybe (catMaybes) +import qualified Data.Text as T +import qualified Data.Text.IO as T +import Language.Haskell.TH.Syntax (Lift(..)) +import Text.Toml +import Text.Toml.Types (Node (VTable, VString), Table) + +managersCsv :: [Char] +managersCsv = "id,manager,age,pay\n\ + \0,Joe,53,\"80,000\"\n\ + \1,Sarah,44,\"80,000\"" + +employeesCsv :: [Char] +employeesCsv = "id,employee,age,pay,manager_id\n\ + \2,Sadie,28,\"40,000\",0\n\ + \3,Tom,25,\"40,000\",1" + +data CsvExample = CsvExample { name :: String, csv :: String, generated :: String } + +instance Lift CsvExample where + lift (CsvExample n c g) = [e| CsvExample n c g |] + +examplesFrom :: FilePath -> IO [CsvExample] +examplesFrom fp = (either error id . ((first show . parseTomlDoc "examples") >=> go)) + <$> T.readFile fp + where go :: Table -> Either String [CsvExample] + go = fmap catMaybes . mapM (uncurry ex . first T.unpack) . H.toList + ex :: String -> Node -> Either String (Maybe CsvExample) + ex k (VTable v) = + do c <- case H.lookup "csv" v of + Nothing -> Right Nothing -- ("No csv key in "++k) + Just (VString c) -> Right (Just (T.unpack c)) + Just _ -> Left ("csv key not a string in " ++ k) + g <- case H.lookup "generated" v of + Nothing -> Left ("No generated key in " ++ k) + Just (VString g) -> Right (Just (T.unpack g)) + Just _ -> Left ("generated key not a string in " ++ k) + return (CsvExample k <$> c <*> g) + ex k _ = Left (k ++ " is not a table") + +generatedFrom :: FilePath -> String -> IO String +generatedFrom fp key = (either error id . (>>= go) + . first show . parseTomlDoc "examples") + <$> T.readFile fp + where go :: Table -> Either String String + go toml = do tbl <- case H.lookup (T.pack key) toml of + Just (VTable t) -> Right t + _ -> Left (key ++ " is not a table") + case H.lookup "generated" tbl of + Just (VString g) -> Right (T.unpack g) + Just _ -> Left ("generated key not a string in " ++ key) + Nothing -> Left ("No generated key in " ++ key) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/test/Overlap.hs new/Frames-0.1.9/test/Overlap.hs --- old/Frames-0.1.4/test/Overlap.hs 1970-01-01 01:00:00.000000000 +0100 +++ new/Frames-0.1.9/test/Overlap.hs 2016-12-06 07:17:45.000000000 +0100 @@ -0,0 +1,12 @@ +{-# LANGUAGE DataKinds, FlexibleContexts, TemplateHaskell #-} +module Main (main) where +import Frames + +-- These data files have overlapping column definitions. Frames should +-- not try to re-define an existing identifier. + +tableTypes "ManagerRec" "test/data/managers.csv" +tableTypes "EmployeeRec" "test/data/employees.csv" + +main :: IO () +main = return () diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/test/PrettyTH.hs new/Frames-0.1.9/test/PrettyTH.hs --- old/Frames-0.1.4/test/PrettyTH.hs 1970-01-01 01:00:00.000000000 +0100 +++ new/Frames-0.1.9/test/PrettyTH.hs 2016-12-06 06:50:45.000000000 +0100 @@ -0,0 +1,61 @@ +{-# LANGUAGE OverloadedStrings #-} +module PrettyTH where +import Data.Char (isSpace) +import Frames +import Language.Haskell.TH +import Language.Haskell.TH.PprLib +import Text.PrettyPrint +import Text.Regex.Applicative + +import Temp + +generateCode :: String -> String -> Q Exp +generateCode rowName txt = + withTempContents + txt + (\fp -> tableTypes rowName fp + >>= stringE + . makePretty + . renderStyle (style {ribbonsPerLine=1.0, lineLength=150}) + . to_HPJ_Doc . ppr) + +-- | Make template haskell-generated code more readable by +-- unqualifying common names, making type operators infix, erasing +-- inferrable types, and adding a bit of whitespace. +makePretty :: String -> String +makePretty = -- Add new lines before type synonym definitions + replace' "\ntype " "\n\ntype " + -- Make :-> and ': type operators infix + . (!! 10) . iterate (replace infixCons) + . replace infixNil + . replace infixCol + -- Erase inferrable type + . replace ((\x y -> x ++ " ∈ " ++ y) + <$> ("RElem " *> some (psym (not . isSpace))) + <*> ((some (psym isSpace) *> some (psym (not . isSpace))) + <* " (RIndex " <* some (psym (/= ')')) <* ")")) + -- Unqualify names + . replace' "Frames.CSV.ParserOptions" "ParserOptions" + . replace' "GHC.Base." "" + . replace' "GHC.Types." "" + . replace' "Data.Vinyl.Core." "" + . replace' "Data.Vinyl.Lens." "" + . replace' "Data.Vinyl.TypeLevel." "" + . replace' "Frames.Rec." "" + . replace' "Frames.RecLens." "" + . replace' "Data.Proxy." "" + . replace' "Data.Text." "T." + . replace' "Data.Text.Internal." "T." + . replace' "'GHC.Types.:" "(':)" + where replace' orig replacement = replace (replacement <$ string orig) + infixCol = (\x y -> '"' : x ++ "\" :-> " ++ y) + <$> ("Frames.Col.:-> \"" *> (some (psym (/= '"'))) <* "\"" + <* some (psym isSpace)) + <*> some (psym (/= ' ')) + infixNil = (\x -> '[' : x ++ "]") + <$> ("((':) (" *> some (psym (/= ')')) <* ")" + <* some (psym isSpace) <* "'[])") + infixCons = (\x y -> '[' : x ++ ", " ++ y ++ "]") + <$> ("((':) (" *> some (psym (/= ')')) <* ")" + <* some (psym isSpace) <* "[") + <*> (some (psym (/= ']')) <* "])") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/test/Spec.hs new/Frames-0.1.9/test/Spec.hs --- old/Frames-0.1.4/test/Spec.hs 1970-01-01 01:00:00.000000000 +0100 +++ new/Frames-0.1.9/test/Spec.hs 2016-12-06 06:50:45.000000000 +0100 @@ -0,0 +1,61 @@ +{-# LANGUAGE CPP, TemplateHaskell, QuasiQuotes #-} +module Main (manualGeneration, main) where +import Data.List (find) +import Data.Monoid (First(..)) +import Language.Haskell.TH as TH +import Language.Haskell.TH.Syntax (addDependentFile) +import Test.Hspec as H +import Frames +import DataCSV +import PrettyTH + +-- | 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) + +-- | Detect type-compatible re-used names and do not attempt to +-- re-generate definitions for them. This does not do the right thing +-- since the generated declarations are never turned into actual +-- declarations, they do not affect the `lookupTypeName` call that is +-- designed to prevent duplicate declarations. +overlappingGeneration :: String +overlappingGeneration = m ++ "\n\n" ++ e + where m = $(do csvExamples <- TH.runIO (examplesFrom "test/examples.toml") + let Just (CsvExample _ managers _) = + find (\(CsvExample k _ _) -> k == "managers") csvExamples + generateCode "ManagerRec" managers) + e = $(do csvExamples <- TH.runIO (examplesFrom "test/examples.toml") + let Just (CsvExample _ employees _) = + find (\(CsvExample k _ _) -> k == "employees") csvExamples + generateCode "EmployeeRec" employees) + +-- | To generate example generated code from raw CSV data, add the csv +-- to @examples.toml@ and set the @generated@ key to an empty +-- string. Then load this file into a REPL that has @:set +-- -XTemplateHaskell@ and evaluate @putStrLn $(manualGeneration +-- "employees")@, for example. +-- +-- 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 k = do csvExamples <- TH.runIO (examplesFrom "test/examples.toml") + maybe (error ("Table " ++ k ++ " not found")) + (generateCode "Row") + (getFirst $ foldMap aux csvExamples) + where aux :: CsvExample -> First String + aux (CsvExample k' c _) = if k == k' then pure c else mempty + +main :: IO () +main = do + hspec $ + do describe "Haskell type generation" $ + mapM_ (\(CsvExample k _ g, g') -> it k (g' `shouldBe` g)) csvTests + describe "Multiple tables" $ + do g <- H.runIO $ + generatedFrom "test/examples.toml" "managers_employees" + it "Shouldn't duplicate columns" pending diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/test/Temp.hs new/Frames-0.1.9/test/Temp.hs --- old/Frames-0.1.4/test/Temp.hs 1970-01-01 01:00:00.000000000 +0100 +++ new/Frames-0.1.9/test/Temp.hs 2016-12-06 06:50:45.000000000 +0100 @@ -0,0 +1,13 @@ +module Temp where +import Language.Haskell.TH +import System.Directory +import System.IO (hClose) +import System.IO.Temp (openTempFile) + +withTempContents :: String -> (FilePath -> Q r) -> Q r +withTempContents contents f = + do fp <- runIO $ do dir <- getTemporaryDirectory + (fp,h) <- openTempFile dir "FramesSpec" + hClose h + fp <$ writeFile fp contents + f fp <* runIO (removeFile fp) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/test/data/employees.csv new/Frames-0.1.9/test/data/employees.csv --- old/Frames-0.1.4/test/data/employees.csv 1970-01-01 01:00:00.000000000 +0100 +++ new/Frames-0.1.9/test/data/employees.csv 2016-12-06 07:03:39.000000000 +0100 @@ -0,0 +1,3 @@ +id,employee,age,pay,manager_id +3,Sadie,28,"40,000",1 +4,Tom,25,"40,000",2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/test/data/managers.csv new/Frames-0.1.9/test/data/managers.csv --- old/Frames-0.1.4/test/data/managers.csv 1970-01-01 01:00:00.000000000 +0100 +++ new/Frames-0.1.9/test/data/managers.csv 2016-12-06 07:03:24.000000000 +0100 @@ -0,0 +1,3 @@ +id,manager,age,pay +1,Joe,53,"80,000" +2,Sarah,44,"80,000" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Frames-0.1.4/test/examples.toml new/Frames-0.1.9/test/examples.toml --- old/Frames-0.1.4/test/examples.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/Frames-0.1.9/test/examples.toml 2016-12-13 19:04:27.000000000 +0100 @@ -0,0 +1,286 @@ +[managers] +csv = """ +id,manager,age,pay +1,Joe,53,"80,000" +2,Sarah,44,"80,000" +""" + +generated = """ +type Row = Record ["id" :-> Int, "manager" :-> T.Text, "age" :-> Int, "pay" :-> Double] +rowParser :: ParserOptions +rowParser = ParserOptions Nothing (T.pack ",") (Frames.CSV.RFC4180Quoting '"') + +type Id = "id" :-> Int +id :: forall f_0 rs_1 . (Functor f_0, Id ∈ rs_1) => + (Int -> f_0 Int) -> Record rs_1 -> f_0 (Record rs_1) +id = rlens (Proxy :: Proxy Id) +id' :: forall f_2 g_3 rs_4 . (Functor f_2, Functor g_3, Id ∈ rs_4) => + (g_3 Id -> f_2 (g_3 Id)) -> Rec g_3 rs_4 -> f_2 (Rec g_3 rs_4) +id' = rlens' (Proxy :: Proxy Id) + +type Manager = "manager" :-> T.Text +manager :: forall f_5 rs_6 . (Functor f_5, Manager ∈ rs_6) => + (T.Text -> f_5 T.Text) -> Record rs_6 -> f_5 (Record rs_6) +manager = rlens (Proxy :: Proxy Manager) +manager' :: forall f_7 g_8 rs_9 . (Functor f_7, + Functor g_8, + Manager ∈ rs_9) => + (g_8 Manager -> f_7 (g_8 Manager)) -> Rec g_8 rs_9 -> f_7 (Rec g_8 rs_9) +manager' = rlens' (Proxy :: Proxy Manager) + +type Age = "age" :-> Int +age :: forall f_10 rs_11 . (Functor f_10, Age ∈ rs_11) => + (Int -> f_10 Int) -> Record rs_11 -> f_10 (Record rs_11) +age = rlens (Proxy :: Proxy Age) +age' :: forall f_12 g_13 rs_14 . (Functor f_12, + Functor g_13, + Age ∈ rs_14) => + (g_13 Age -> f_12 (g_13 Age)) -> Rec g_13 rs_14 -> f_12 (Rec g_13 rs_14) +age' = rlens' (Proxy :: Proxy Age) + +type Pay = "pay" :-> Double +pay :: forall f_15 rs_16 . (Functor f_15, Pay ∈ rs_16) => + (Double -> f_15 Double) -> Record rs_16 -> f_15 (Record rs_16) +pay = rlens (Proxy :: Proxy Pay) +pay' :: forall f_17 g_18 rs_19 . (Functor f_17, + Functor g_18, + Pay ∈ rs_19) => + (g_18 Pay -> f_17 (g_18 Pay)) -> Rec g_18 rs_19 -> f_17 (Rec g_18 rs_19) +pay' = rlens' (Proxy :: Proxy Pay)""" + +[employees] +csv = """ +id,employee,age,pay,manager_id +3,Sadie,28,"40,000",1 +4,Tom,25,"40,000",2 +""" + +generated = """ +type Row = Record ["id" :-> Int, "employee" :-> T.Text, "age" :-> Int, "pay" :-> Double, "manager_id" :-> Int] +rowParser :: ParserOptions +rowParser = ParserOptions Nothing (T.pack ",") (Frames.CSV.RFC4180Quoting '"') + +type Id = "id" :-> Int +id :: forall f_0 rs_1 . (Functor f_0, Id ∈ rs_1) => + (Int -> f_0 Int) -> Record rs_1 -> f_0 (Record rs_1) +id = rlens (Proxy :: Proxy Id) +id' :: forall f_2 g_3 rs_4 . (Functor f_2, Functor g_3, Id ∈ rs_4) => + (g_3 Id -> f_2 (g_3 Id)) -> Rec g_3 rs_4 -> f_2 (Rec g_3 rs_4) +id' = rlens' (Proxy :: Proxy Id) + +type Employee = "employee" :-> T.Text +employee :: forall f_5 rs_6 . (Functor f_5, Employee ∈ rs_6) => + (T.Text -> f_5 T.Text) -> Record rs_6 -> f_5 (Record rs_6) +employee = rlens (Proxy :: Proxy Employee) +employee' :: forall f_7 g_8 rs_9 . (Functor f_7, + Functor g_8, + Employee ∈ rs_9) => + (g_8 Employee -> f_7 (g_8 Employee)) -> Rec g_8 rs_9 -> f_7 (Rec g_8 rs_9) +employee' = rlens' (Proxy :: Proxy Employee) + +type Age = "age" :-> Int +age :: forall f_10 rs_11 . (Functor f_10, Age ∈ rs_11) => + (Int -> f_10 Int) -> Record rs_11 -> f_10 (Record rs_11) +age = rlens (Proxy :: Proxy Age) +age' :: forall f_12 g_13 rs_14 . (Functor f_12, + Functor g_13, + Age ∈ rs_14) => + (g_13 Age -> f_12 (g_13 Age)) -> Rec g_13 rs_14 -> f_12 (Rec g_13 rs_14) +age' = rlens' (Proxy :: Proxy Age) + +type Pay = "pay" :-> Double +pay :: forall f_15 rs_16 . (Functor f_15, Pay ∈ rs_16) => + (Double -> f_15 Double) -> Record rs_16 -> f_15 (Record rs_16) +pay = rlens (Proxy :: Proxy Pay) +pay' :: forall f_17 g_18 rs_19 . (Functor f_17, + Functor g_18, + Pay ∈ rs_19) => + (g_18 Pay -> f_17 (g_18 Pay)) -> Rec g_18 rs_19 -> f_17 (Rec g_18 rs_19) +pay' = rlens' (Proxy :: Proxy Pay) + +type ManagerId = "manager_id" :-> Int +managerId :: forall f_20 rs_21 . (Functor f_20, ManagerId ∈ rs_21) => + (Int -> f_20 Int) -> Record rs_21 -> f_20 (Record rs_21) +managerId = rlens (Proxy :: Proxy ManagerId) +managerId' :: forall f_22 g_23 rs_24 . (Functor f_22, + Functor g_23, + ManagerId ∈ rs_24) => + (g_23 ManagerId -> f_22 (g_23 ManagerId)) -> + Rec g_23 rs_24 -> f_22 (Rec g_23 rs_24) +managerId' = rlens' (Proxy :: Proxy ManagerId)""" + +[managers_employees] +generated = """ +type ManagerRec = Record ["id" :-> Int, "manager" :-> T.Text, "age" :-> Int, "pay" :-> Double] +managerRecParser :: ParserOptions +managerRecParser = ParserOptions Nothing (T.pack ",") (Frames.CSV.RFC4180Quoting '"') + +type Id = "id" :-> Int +id :: forall f_0 rs_1 . (Functor f_0, Id ∈ rs_1) => + (Int -> f_0 Bool) -> Record rs_1 -> f_0 (Record rs_1) +id = rlens (Proxy :: Proxy Id) +id' :: forall f_2 g_3 rs_4 . (Functor f_2, Functor g_3, Id ∈ rs_4) => + (g_3 Id -> f_2 (g_3 Id)) -> Rec g_3 rs_4 -> f_2 (Rec g_3 rs_4) +id' = rlens' (Proxy :: Proxy Id) + +type Manager = "manager" :-> T.Text +manager :: forall f_5 rs_6 . (Functor f_5, Manager ∈ rs_6) => + (T.Text -> f_5 T.Text) -> Record rs_6 -> f_5 (Record rs_6) +manager = rlens (Proxy :: Proxy Manager) +manager' :: forall f_7 g_8 rs_9 . (Functor f_7, + Functor g_8, + Manager ∈ rs_9) => + (g_8 Manager -> f_7 (g_8 Manager)) -> Rec g_8 rs_9 -> f_7 (Rec g_8 rs_9) +manager' = rlens' (Proxy :: Proxy Manager) + +type Age = "age" :-> Int +age :: forall f_10 rs_11 . (Functor f_10, Age ∈ rs_11) => + (Int -> f_10 Int) -> Record rs_11 -> f_10 (Record rs_11) +age = rlens (Proxy :: Proxy Age) +age' :: forall f_12 g_13 rs_14 . (Functor f_12, + Functor g_13, + Age ∈ rs_14) => + (g_13 Age -> f_12 (g_13 Age)) -> Rec g_13 rs_14 -> f_12 (Rec g_13 rs_14) +age' = rlens' (Proxy :: Proxy Age) + +type Pay = "pay" :-> Double +pay :: forall f_15 rs_16 . (Functor f_15, Pay ∈ rs_16) => + (Double -> f_15 Double) -> Record rs_16 -> f_15 (Record rs_16) +pay = rlens (Proxy :: Proxy Pay) +pay' :: forall f_17 g_18 rs_19 . (Functor f_17, + Functor g_18, + Pay ∈ rs_19) => + (g_18 Pay -> f_17 (g_18 Pay)) -> Rec g_18 rs_19 -> f_17 (Rec g_18 rs_19) +pay' = rlens' (Proxy :: Proxy Pay) + +type EmployeeRec = Record ["id" :-> Int, "employee" :-> T.Text, "age" :-> Int, "pay" :-> Double, "manager_id" :-> Int] +employeeRecParser :: ParserOptions +employeeRecParser = ParserOptions Nothing (T.pack ",") (Frames.CSV.RFC4180Quoting '"') + +type Employee = "employee" :-> T.Text +employee :: forall f_5 rs_6 . (Functor f_5, Employee ∈ rs_6) => + (T.Text -> f_5 T.Text) -> Record rs_6 -> f_5 (Record rs_6) +employee = rlens (Proxy :: Proxy Employee) +employee' :: forall f_7 g_8 rs_9 . (Functor f_7, + Functor g_8, + Employee ∈ rs_9) => + (g_8 Employee -> f_7 (g_8 Employee)) -> Rec g_8 rs_9 -> f_7 (Rec g_8 rs_9) +employee' = rlens' (Proxy :: Proxy Employee) + +type Age = "age" :-> Int + +type ManagerId = "manager_id" :-> Int +managerId :: forall f_20 rs_21 . (Functor f_20, ManagerId ∈ rs_21) => + (Int -> f_20 Int) -> Record rs_21 -> f_20 (Record rs_21) +managerId = rlens (Proxy :: Proxy ManagerId) +managerId' :: forall f_22 g_23 rs_24 . (Functor f_22, + Functor g_23, + ManagerId ∈ rs_24) => + (g_23 ManagerId -> f_22 (g_23 ManagerId)) -> + Rec g_23 rs_24 -> f_22 (Rec g_23 rs_24) +managerId' = rlens' (Proxy :: Proxy ManagerId) +""" + +[double_gt_bool] +csv = """ +col_a,col_b,col_c +1,9,"1,000,000.00" +2,8,"300,000.00" +3,7,"0" +4,6,0 +""" + +generated = """ +type Row = Record ["col_a" :-> Int, "col_b" :-> Int, "col_c" :-> Double] +rowParser :: ParserOptions +rowParser = ParserOptions Nothing (T.pack ",") (Frames.CSV.RFC4180Quoting '"') + +type ColA = "col_a" :-> Int +colA :: forall f_0 rs_1 . (Functor f_0, ColA ∈ rs_1) => + (Int -> f_0 Int) -> Record rs_1 -> f_0 (Record rs_1) +colA = rlens (Proxy :: Proxy ColA) +colA' :: forall f_2 g_3 rs_4 . (Functor f_2, + Functor g_3, + ColA ∈ rs_4) => + (g_3 ColA -> f_2 (g_3 ColA)) -> Rec g_3 rs_4 -> f_2 (Rec g_3 rs_4) +colA' = rlens' (Proxy :: Proxy ColA) + +type ColB = "col_b" :-> Int +colB :: forall f_5 rs_6 . (Functor f_5, ColB ∈ rs_6) => + (Int -> f_5 Int) -> Record rs_6 -> f_5 (Record rs_6) +colB = rlens (Proxy :: Proxy ColB) +colB' :: forall f_7 g_8 rs_9 . (Functor f_7, + Functor g_8, + ColB ∈ rs_9) => + (g_8 ColB -> f_7 (g_8 ColB)) -> Rec g_8 rs_9 -> f_7 (Rec g_8 rs_9) +colB' = rlens' (Proxy :: Proxy ColB) + +type ColC = "col_c" :-> Double +colC :: forall f_10 rs_11 . (Functor f_10, ColC ∈ rs_11) => + (Double -> f_10 Double) -> Record rs_11 -> f_10 (Record rs_11) +colC = rlens (Proxy :: Proxy ColC) +colC' :: forall f_12 g_13 rs_14 . (Functor f_12, + Functor g_13, + ColC ∈ rs_14) => + (g_13 ColC -> f_12 (g_13 ColC)) -> Rec g_13 rs_14 -> f_12 (Rec g_13 rs_14) +colC' = rlens' (Proxy :: Proxy ColC)""" + +[text_gt_bool] +csv = """ +col_a +"0" +"0" +"0" +"0" +A +""" + +generated = """ +type Row = Record ["col_a" :-> T.Text] +rowParser :: ParserOptions +rowParser = ParserOptions Nothing (T.pack ",") (Frames.CSV.RFC4180Quoting '"') + +type ColA = "col_a" :-> T.Text +colA :: forall f_0 rs_1 . (Functor f_0, ColA ∈ rs_1) => + (T.Text -> f_0 T.Text) -> Record rs_1 -> f_0 (Record rs_1) +colA = rlens (Proxy :: Proxy ColA) +colA' :: forall f_2 g_3 rs_4 . (Functor f_2, + Functor g_3, + ColA ∈ rs_4) => + (g_3 ColA -> f_2 (g_3 ColA)) -> Rec g_3 rs_4 -> f_2 (Rec g_3 rs_4) +colA' = rlens' (Proxy :: Proxy ColA)""" + +[missing_data] +csv = """ +col_a,col_b +"0","x" +"2","x" +"1","x" +,"x" +"0","x" +""" + +generated = """ +type Row = Record ["col_a" :-> Int, "col_b" :-> T.Text] +rowParser :: ParserOptions +rowParser = ParserOptions Nothing (T.pack ",") (Frames.CSV.RFC4180Quoting '"') + +type ColA = "col_a" :-> Int +colA :: forall f_0 rs_1 . (Functor f_0, ColA ∈ rs_1) => + (Int -> f_0 Int) -> Record rs_1 -> f_0 (Record rs_1) +colA = rlens (Proxy :: Proxy ColA) +colA' :: forall f_2 g_3 rs_4 . (Functor f_2, + Functor g_3, + ColA ∈ rs_4) => + (g_3 ColA -> f_2 (g_3 ColA)) -> Rec g_3 rs_4 -> f_2 (Rec g_3 rs_4) +colA' = rlens' (Proxy :: Proxy ColA) + +type ColB = "col_b" :-> T.Text +colB :: forall f_5 rs_6 . (Functor f_5, ColB ∈ rs_6) => + (T.Text -> f_5 T.Text) -> Record rs_6 -> f_5 (Record rs_6) +colB = rlens (Proxy :: Proxy ColB) +colB' :: forall f_7 g_8 rs_9 . (Functor f_7, + Functor g_8, + ColB ∈ rs_9) => + (g_8 ColB -> f_7 (g_8 ColB)) -> Rec g_8 rs_9 -> f_7 (Rec g_8 rs_9) +colB' = rlens' (Proxy :: Proxy ColB)"""