packages feed

dataframe 0.3.5.0 → 0.4.0.0

raw patch · 12 files changed

+526/−308 lines, 12 filesdep +zlibdep ~dataframePVP ok

version bump matches the API change (PVP)

Dependencies added: zlib

Dependency ranges changed: dataframe

API changes (from Hackage documentation)

+ DataFrame: [columnSeparator] :: ReadOptions -> Char
+ DataFrame: columnAsUnboxedVector :: (Columnable a, Unbox a) => Expr a -> DataFrame -> Either DataFrameException (Vector a)
+ DataFrame: meanMaybe :: (Columnable a, Real a) => Expr (Maybe a) -> DataFrame -> Double
+ DataFrame.Functions: (./=) :: (Columnable a, Eq a) => Expr a -> Expr a -> Expr Bool
+ DataFrame.Functions: declareColumnsFromCsvWithOpts :: ReadOptions -> String -> DecsQ
+ DataFrame.Functions: declareColumnsFromParquetFile :: String -> DecsQ
+ DataFrame.IO.CSV: [columnSeparator] :: ReadOptions -> Char
+ DataFrame.Monad: evalFrameM :: DataFrame -> FrameM a -> a
+ DataFrame.Monad: execFrameM :: DataFrame -> FrameM a -> DataFrame
+ DataFrame.Monad: filterJustM :: Columnable a => Expr (Maybe a) -> FrameM (Expr a)
+ DataFrame.Monad: imputeM :: Columnable a => Expr (Maybe a) -> a -> FrameM (Expr a)
+ DataFrame.Monad: inspectM :: (DataFrame -> b) -> FrameM b
+ DataFrame.Monad: modifyM :: (DataFrame -> DataFrame) -> FrameM ()
+ DataFrame.Operations.Core: columnAsDoubleVector :: Expr Double -> DataFrame -> Either DataFrameException (Vector Double)
+ DataFrame.Operations.Core: columnAsFloatVector :: Expr Float -> DataFrame -> Either DataFrameException (Vector Float)
+ DataFrame.Operations.Core: columnAsIntVector :: Expr Int -> DataFrame -> Either DataFrameException (Vector Int)
+ DataFrame.Operations.Core: columnAsList :: Columnable a => Expr a -> DataFrame -> [a]
+ DataFrame.Operations.Core: columnAsUnboxedVector :: (Columnable a, Unbox a) => Expr a -> DataFrame -> Either DataFrameException (Vector a)
+ DataFrame.Operations.Core: columnAsVector :: Columnable a => Expr a -> DataFrame -> Vector a
+ DataFrame.Operations.Core: toDoubleMatrix :: DataFrame -> Either DataFrameException (Vector (Vector Double))
+ DataFrame.Operations.Core: toFloatMatrix :: DataFrame -> Either DataFrameException (Vector (Vector Float))
+ DataFrame.Operations.Core: toIntMatrix :: DataFrame -> Either DataFrameException (Vector (Vector Int))
+ DataFrame.Synthesis: isConditional :: Expr a -> Bool
- DataFrame: ReadOptions :: HeaderSpec -> TypeSpec -> Bool -> String -> ReadOptions
+ DataFrame: ReadOptions :: HeaderSpec -> TypeSpec -> Bool -> String -> Char -> ReadOptions
- DataFrame: columnAsDoubleVector :: Text -> DataFrame -> Either DataFrameException (Vector Double)
+ DataFrame: columnAsDoubleVector :: Expr Double -> DataFrame -> Either DataFrameException (Vector Double)
- DataFrame: columnAsFloatVector :: Text -> DataFrame -> Either DataFrameException (Vector Float)
+ DataFrame: columnAsFloatVector :: Expr Float -> DataFrame -> Either DataFrameException (Vector Float)
- DataFrame: columnAsIntVector :: Text -> DataFrame -> Either DataFrameException (Vector Int)
+ DataFrame: columnAsIntVector :: Expr Int -> DataFrame -> Either DataFrameException (Vector Int)
- DataFrame: columnAsList :: Columnable a => Text -> DataFrame -> [a]
+ DataFrame: columnAsList :: Columnable a => Expr a -> DataFrame -> [a]
- DataFrame: columnAsVector :: Columnable a => Text -> DataFrame -> Vector a
+ DataFrame: columnAsVector :: Columnable a => Expr a -> DataFrame -> Vector a
- DataFrame: readSeparated :: Char -> ReadOptions -> FilePath -> IO DataFrame
+ DataFrame: readSeparated :: ReadOptions -> FilePath -> IO DataFrame
- DataFrame.IO.CSV: ReadOptions :: HeaderSpec -> TypeSpec -> Bool -> String -> ReadOptions
+ DataFrame.IO.CSV: ReadOptions :: HeaderSpec -> TypeSpec -> Bool -> String -> Char -> ReadOptions
- DataFrame.IO.CSV: readSeparated :: Char -> ReadOptions -> FilePath -> IO DataFrame
+ DataFrame.IO.CSV: readSeparated :: ReadOptions -> FilePath -> IO DataFrame
- DataFrame.IO.Parquet.Thrift: readAesGcmCtrV1 :: EncryptionAlgorithm -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO EncryptionAlgorithm
+ DataFrame.IO.Parquet.Thrift: readAesGcmCtrV1 :: EncryptionAlgorithm -> ByteString -> IORef Int -> Int16 -> IO EncryptionAlgorithm
- DataFrame.IO.Parquet.Thrift: readAesGcmV1 :: EncryptionAlgorithm -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO EncryptionAlgorithm
+ DataFrame.IO.Parquet.Thrift: readAesGcmV1 :: EncryptionAlgorithm -> ByteString -> IORef Int -> Int16 -> IO EncryptionAlgorithm
- DataFrame.IO.Parquet.Thrift: readColumnChunk :: ColumnChunk -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO ColumnChunk
+ DataFrame.IO.Parquet.Thrift: readColumnChunk :: ColumnChunk -> ByteString -> IORef Int -> Int16 -> IO ColumnChunk
- DataFrame.IO.Parquet.Thrift: readColumnMetadata :: ColumnMetaData -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO ColumnMetaData
+ DataFrame.IO.Parquet.Thrift: readColumnMetadata :: ColumnMetaData -> ByteString -> IORef Int -> Int16 -> IO ColumnMetaData
- DataFrame.IO.Parquet.Thrift: readColumnOrder :: ByteString -> IORef Int -> Int16 -> [Int16] -> IO ColumnOrder
+ DataFrame.IO.Parquet.Thrift: readColumnOrder :: ByteString -> IORef Int -> Int16 -> IO ColumnOrder
- DataFrame.IO.Parquet.Thrift: readDecimalType :: Int32 -> Int32 -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO LogicalType
+ DataFrame.IO.Parquet.Thrift: readDecimalType :: Int32 -> Int32 -> ByteString -> IORef Int -> Int16 -> IO LogicalType
- DataFrame.IO.Parquet.Thrift: readEncryptionAlgorithm :: ByteString -> IORef Int -> Int16 -> [Int16] -> IO EncryptionAlgorithm
+ DataFrame.IO.Parquet.Thrift: readEncryptionAlgorithm :: ByteString -> IORef Int -> Int16 -> IO EncryptionAlgorithm
- DataFrame.IO.Parquet.Thrift: readField :: ByteString -> IORef Int -> Int16 -> [Int16] -> IO (Maybe (TType, Int16))
+ DataFrame.IO.Parquet.Thrift: readField :: ByteString -> IORef Int -> Int16 -> IO (Maybe (TType, Int16))
- DataFrame.IO.Parquet.Thrift: readFileMetaData :: FileMetadata -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO FileMetadata
+ DataFrame.IO.Parquet.Thrift: readFileMetaData :: FileMetadata -> ByteString -> IORef Int -> Int16 -> IO FileMetadata
- DataFrame.IO.Parquet.Thrift: readIntType :: Int8 -> Bool -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO LogicalType
+ DataFrame.IO.Parquet.Thrift: readIntType :: Int8 -> Bool -> ByteString -> IORef Int -> Int16 -> IO LogicalType
- DataFrame.IO.Parquet.Thrift: readKeyValue :: KeyValue -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO KeyValue
+ DataFrame.IO.Parquet.Thrift: readKeyValue :: KeyValue -> ByteString -> IORef Int -> Int16 -> IO KeyValue
- DataFrame.IO.Parquet.Thrift: readLogicalType :: ByteString -> IORef Int -> Int16 -> [Int16] -> IO LogicalType
+ DataFrame.IO.Parquet.Thrift: readLogicalType :: LogicalType -> ByteString -> IORef Int -> Int16 -> IO LogicalType
- DataFrame.IO.Parquet.Thrift: readPageEncodingStats :: PageEncodingStats -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO PageEncodingStats
+ DataFrame.IO.Parquet.Thrift: readPageEncodingStats :: PageEncodingStats -> ByteString -> IORef Int -> Int16 -> IO PageEncodingStats
- DataFrame.IO.Parquet.Thrift: readParquetEncoding :: ByteString -> IORef Int -> Int16 -> [Int16] -> IO ParquetEncoding
+ DataFrame.IO.Parquet.Thrift: readParquetEncoding :: ByteString -> IORef Int -> Int16 -> IO ParquetEncoding
- DataFrame.IO.Parquet.Thrift: readRowGroup :: RowGroup -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO RowGroup
+ DataFrame.IO.Parquet.Thrift: readRowGroup :: RowGroup -> ByteString -> IORef Int -> Int16 -> IO RowGroup
- DataFrame.IO.Parquet.Thrift: readSchemaElement :: SchemaElement -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO SchemaElement
+ DataFrame.IO.Parquet.Thrift: readSchemaElement :: SchemaElement -> ByteString -> IORef Int -> Int16 -> IO SchemaElement
- DataFrame.IO.Parquet.Thrift: readSizeStatistics :: SizeStatistics -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO SizeStatistics
+ DataFrame.IO.Parquet.Thrift: readSizeStatistics :: SizeStatistics -> ByteString -> IORef Int -> Int16 -> IO SizeStatistics
- DataFrame.IO.Parquet.Thrift: readStatistics :: ColumnStatistics -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO ColumnStatistics
+ DataFrame.IO.Parquet.Thrift: readStatistics :: ColumnStatistics -> ByteString -> IORef Int -> Int16 -> IO ColumnStatistics
- DataFrame.IO.Parquet.Thrift: readTimeType :: Bool -> TimeUnit -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO LogicalType
+ DataFrame.IO.Parquet.Thrift: readTimeType :: Bool -> TimeUnit -> ByteString -> IORef Int -> Int16 -> IO LogicalType
- DataFrame.IO.Parquet.Thrift: readTimestampType :: Bool -> TimeUnit -> ByteString -> IORef Int -> Int16 -> [Int16] -> IO LogicalType
+ DataFrame.IO.Parquet.Thrift: readTimestampType :: Bool -> TimeUnit -> ByteString -> IORef Int -> Int16 -> IO LogicalType
- DataFrame.IO.Parquet.Thrift: readTypeOrder :: ByteString -> IORef Int -> Int16 -> [Int16] -> IO ColumnOrder
+ DataFrame.IO.Parquet.Thrift: readTypeOrder :: ByteString -> IORef Int -> Int16 -> IO ColumnOrder
- DataFrame.IO.Parquet.Thrift: readUnit :: ByteString -> IORef Int -> Int16 -> [Int16] -> IO TimeUnit
+ DataFrame.IO.Parquet.Thrift: readUnit :: TimeUnit -> ByteString -> IORef Int -> Int16 -> IO TimeUnit
- DataFrame.Monad: runFrameM :: DataFrame -> FrameM a -> DataFrame
+ DataFrame.Monad: runFrameM :: DataFrame -> FrameM a -> (a, DataFrame)

Files

CHANGELOG.md view
@@ -1,5 +1,37 @@ # Revision history for dataframe +## 0.4.0.0+* `readSeparated` no longer takes the separator as an argument. This is not placed into readOptions.+* Some improvements to the synthesis demo+* Add a `declareColumnsParquetFile` function. +* Column conversion functions now take expressions instead of strings.+* Add more monadic functions to make previously tricky transformations easier to write:+    ```haskell+    {-# LANGUAGE OverloadedStrings #-}+    {-# LANGUAGE TemplateHaskell #-}++    module Main where++    import qualified DataFrame as D+    import qualified DataFrame.Functions as F++    import DataFrame.Monad++    import Data.Text (Text)+    import DataFrame.Functions ((.&&), (.>=))++    $(F.declareColumnsFromCsvFile "./data/housing.csv")++    main :: IO ()+    main = do+        df <- D.readCsv "./data/housing.csv"+        print $ execFrameM df $ do+            is_expensive <- deriveM "is_expensive" (median_house_value .>= 500000)+            meanBedrooms <- inspectM (D.meanMaybe total_bedrooms)+            totalBedrooms <- imputeM total_bedrooms meanBedrooms+            filterWhereM (totalBedrooms .>= 200 .&& is_expensive)+    ```+ ## 0.3.5.0 * Add a `deriveWithExpr` that returns an expression that you can use in a subsequent expressions. * Add `declareColumnsFromCsvFile` which can create the expressions up front for use in scripts.
dataframe.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               dataframe-version:            0.3.5.0+version:            0.4.0.0  synopsis: A fast, safe, and intuitive DataFrame library. @@ -107,6 +107,7 @@                       unordered-containers >= 0.1 && < 1,                       vector ^>= 0.13,                       vector-algorithms ^>= 0.9,+                      zlib >= 0.5 && < 1,                       zstd >= 0.1.2.0 && < 0.2,                       mmap >= 0.5.8 && <= 0.5.9,                       parallel >= 3.2.2.0 && < 5@@ -121,7 +122,7 @@     import: warnings     main-is: Benchmark.hs     build-depends:    base >= 4 && < 5,-                      dataframe ^>= 0.3,+                      dataframe ^>= 0.4,                       random >= 1 && < 2,                       time >= 1.12 && < 2,                       vector ^>= 0.13,@@ -150,7 +151,7 @@     build-depends: base >= 4 && < 5,                    criterion >= 1 && < 2,                    process >= 1.6 && < 2,-                   dataframe ^>= 0.3+                   dataframe ^>= 0.4     default-language: Haskell2010     ghc-options:       -threaded@@ -178,7 +179,7 @@                    Operations.Take,                    Parquet     build-depends:  base >= 4 && < 5,-                    dataframe ^>= 0.3,+                    dataframe ^>= 0.4,                     HUnit ^>= 1.6,                     random >= 1 && < 2,                     random-shuffle >= 0.0.4 && < 1,
src/DataFrame.hs view
@@ -270,16 +270,8 @@ import DataFrame.Internal.DataFrame as Dataframe (     DataFrame,     GroupedDataFrame,-    columnAsDoubleVector,-    columnAsFloatVector,-    columnAsIntVector,-    columnAsList,-    columnAsVector,     empty,     null,-    toDoubleMatrix,-    toFloatMatrix,-    toIntMatrix,     toMarkdownTable,  ) import DataFrame.Internal.Expression as Expression (Expr)@@ -317,6 +309,7 @@     imputeWith,     interQuartileRange,     mean,+    meanMaybe,     median,     skewness,     standardDeviation,
src/DataFrame/Functions.hs view
@@ -39,6 +39,7 @@ import qualified Data.Vector as V import qualified Data.Vector.Unboxed as VU import qualified DataFrame.IO.CSV as CSV+import qualified DataFrame.IO.Parquet as Parquet import Debug.Trace (trace) import Language.Haskell.TH import qualified Language.Haskell.TH.Syntax as TH@@ -46,7 +47,7 @@ import Prelude hiding (maximum, minimum) import Prelude as P -infix 4 .==, .<, .<=, .>=, .>+infix 4 .==, .<, .<=, .>=, .>, ./= infixr 3 .&& infixr 2 .|| @@ -92,6 +93,9 @@ (.==) :: (Columnable a, Eq a) => Expr a -> Expr a -> Expr Bool (.==) = BinaryOp "eq" (==) +(./=) :: (Columnable a, Eq a) => Expr a -> Expr a -> Expr Bool+(./=) = BinaryOp "eq" (/=)+ eq :: (Columnable a, Eq a) => Expr a -> Expr a -> Expr Bool eq = BinaryOp "eq" (==) @@ -101,11 +105,15 @@ lt :: (Columnable a, Ord a) => Expr a -> Expr a -> Expr Bool lt = BinaryOp "lt" (<) +-- TODO: Generalize this pattern for other equality functions. (.>) :: (Columnable a, Ord a) => Expr a -> Expr a -> Expr Bool-(.>) = BinaryOp "gt" (>)+(.>) (Lit l) (Lit r) = Lit (l > r)+(.>) (Lit l) expr = UnaryOp ("gt " <> T.pack (show l)) (l >) expr+(.>) expr (Lit r) = UnaryOp ("leq " <> T.pack (show r)) (r <=) expr+(.>) l r = BinaryOp "gt" (>) l r  gt :: (Columnable a, Ord a) => Expr a -> Expr a -> Expr Bool-gt = BinaryOp "gt" (>)+gt = (.>)  (.<=) :: (Columnable a, Ord a, Eq a) => Expr a -> Expr a -> Expr Bool (.<=) = BinaryOp "leq" (<=)@@ -203,6 +211,7 @@  pow :: (Columnable a, Num a) => Expr a -> Int -> Expr a pow _ 0 = Lit 1+pow (Lit n) i = Lit (n ^ i) pow expr 1 = expr pow expr i = UnaryOp ("pow " <> T.pack (show i)) (^ i) expr @@ -363,6 +372,17 @@ declareColumnsFromCsvFile :: String -> DecsQ declareColumnsFromCsvFile path = do     df <- liftIO (CSV.readCsv path)+    declareColumns df++-- TODO: We don't have to read the whole file, we can just read the schema.+declareColumnsFromParquetFile :: String -> DecsQ+declareColumnsFromParquetFile path = do+    df <- liftIO (Parquet.readParquet path)+    declareColumns df++declareColumnsFromCsvWithOpts :: CSV.ReadOptions -> String -> DecsQ+declareColumnsFromCsvWithOpts opts path = do+    df <- liftIO (CSV.readSeparated opts path)     declareColumns df  declareColumns :: DataFrame -> DecsQ
src/DataFrame/IO/CSV.hs view
@@ -163,6 +163,8 @@     Just 2010-03-04     @     -}+    , columnSeparator :: Char+    -- ^ Character that separates column values.     }  shouldInferFromSample :: TypeSpec -> Bool@@ -184,6 +186,7 @@         , typeSpec = InferFromSample 100         , safeRead = True         , dateFormat = "%Y-%m-%d"+        , columnSeparator = ','         }  {- | Read CSV file from path and load it into a dataframe.@@ -195,7 +198,7 @@ @ -} readCsv :: FilePath -> IO DataFrame-readCsv = readSeparated ',' defaultReadOptions+readCsv = readSeparated defaultReadOptions  {- | Read CSV file from path and load it into a dataframe. @@ -206,7 +209,7 @@ @ -} readCsvWithOpts :: ReadOptions -> FilePath -> IO DataFrame-readCsvWithOpts = readSeparated ','+readCsvWithOpts = readSeparated  {- | Read TSV (tab separated) file from path and load it into a dataframe. @@ -217,18 +220,19 @@ @ -} readTsv :: FilePath -> IO DataFrame-readTsv = readSeparated '\t' defaultReadOptions+readTsv = readSeparated (defaultReadOptions{columnSeparator = '\t'})  {- | Read text file with specified delimiter into a dataframe.  ==== __Example__ @-ghci> D.readSeparated ';' D.defaultReadOptions ".\/data\/taxi.txt"+ghci> D.readSeparated (D.defaultReadOptions { columnSeparator = ';' }) ".\/data\/taxi.txt"  @ -}-readSeparated :: Char -> ReadOptions -> FilePath -> IO DataFrame-readSeparated !sep !opts !path = do+readSeparated :: ReadOptions -> FilePath -> IO DataFrame+readSeparated !opts !path = do+    let sep = columnSeparator opts     csvData <- BL.readFile path     let decodeOpts = Csv.defaultDecodeOptions{Csv.decDelimiter = fromIntegral (ord sep)}     let stream = CsvStream.decodeWith decodeOpts Csv.NoHeader csvData
src/DataFrame/IO/Parquet/Page.hs view
@@ -3,9 +3,11 @@  module DataFrame.IO.Parquet.Page where +import qualified Codec.Compression.GZip as GZip import Codec.Compression.Zstd.Streaming import Data.Bits import qualified Data.ByteString as BSO+import qualified Data.ByteString.Lazy as LB import Data.Int import Data.Maybe (fromMaybe, listToMaybe) import Data.Word@@ -42,6 +44,7 @@             Left e -> error (show e)             Right res -> pure res         UNCOMPRESSED -> pure (BSO.pack compressed)+        GZIP -> pure (LB.toStrict (GZip.decompress (LB.pack compressed)))         other -> error ("Unsupported compression type: " ++ show other)     pure         ( Just $ Page hdr (BSO.unpack fullData)
src/DataFrame/IO/Parquet/Thrift.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StrictData #-} {-# LANGUAGE TypeApplications #-}  module DataFrame.IO.Parquet.Thrift where@@ -202,8 +203,8 @@                 ]  readField ::-    BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO (Maybe (TType, Int16))-readField buf pos lastFieldId fieldStack = do+    BS.ByteString -> IORef Int -> Int16 -> IO (Maybe (TType, Int16))+readField buf pos lastFieldId = do     t <- readAndAdvance pos buf     if t .&. 0x0f == 0         then return Nothing@@ -256,19 +257,17 @@             BS.pack $                 map (BS.index contents) [metadataStartPos .. (metadataStartPos + size - 1)]     let lastFieldId = 0-    let fieldStack = []     bufferPos <- newIORef (0 :: Int)-    readFileMetaData defaultMetadata metadataBytes bufferPos lastFieldId fieldStack+    readFileMetaData defaultMetadata metadataBytes bufferPos lastFieldId  readFileMetaData ::     FileMetadata ->     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO FileMetadata-readFileMetaData metadata metaDataBuf bufferPos lastFieldId fieldStack = do-    fieldContents <- readField metaDataBuf bufferPos lastFieldId fieldStack+readFileMetaData metadata metaDataBuf bufferPos lastFieldId = do+    fieldContents <- readField metaDataBuf bufferPos lastFieldId     case fieldContents of         Nothing -> return metadata         Just (elemType, identifier) -> case identifier of@@ -279,7 +278,6 @@                     metaDataBuf                     bufferPos                     identifier-                    fieldStack             2 -> do                 sizeAndType <- readAndAdvance bufferPos metaDataBuf                 listSize <-@@ -290,13 +288,12 @@                 schemaElements <-                     replicateM                         listSize-                        (readSchemaElement defaultSchemaElement metaDataBuf bufferPos 0 [])+                        (readSchemaElement defaultSchemaElement metaDataBuf bufferPos 0)                 readFileMetaData                     (metadata{schema = schemaElements})                     metaDataBuf                     bufferPos                     identifier-                    fieldStack             3 -> do                 numRows <- readIntFromBuffer @Int64 metaDataBuf bufferPos                 readFileMetaData@@ -304,7 +301,6 @@                     metaDataBuf                     bufferPos                     identifier-                    fieldStack             4 -> do                 sizeAndType <- readAndAdvance bufferPos metaDataBuf                 listSize <-@@ -315,13 +311,12 @@                 -- TODO actually check elemType agrees (also for all the other underscored _elemType in this module)                 let _elemType = toTType sizeAndType                 rowGroups <--                    replicateM listSize (readRowGroup emptyRowGroup metaDataBuf bufferPos 0 [])+                    replicateM listSize (readRowGroup emptyRowGroup metaDataBuf bufferPos 0)                 readFileMetaData                     (metadata{rowGroups = rowGroups})                     metaDataBuf                     bufferPos                     identifier-                    fieldStack             5 -> do                 sizeAndType <- readAndAdvance bufferPos metaDataBuf                 listSize <-@@ -331,13 +326,12 @@                  let _elemType = toTType sizeAndType                 keyValueMetadata <--                    replicateM listSize (readKeyValue emptyKeyValue metaDataBuf bufferPos 0 [])+                    replicateM listSize (readKeyValue emptyKeyValue metaDataBuf bufferPos 0)                 readFileMetaData                     (metadata{keyValueMetadata = keyValueMetadata})                     metaDataBuf                     bufferPos                     identifier-                    fieldStack             6 -> do                 createdBy <- readString metaDataBuf bufferPos                 readFileMetaData@@ -345,7 +339,6 @@                     metaDataBuf                     bufferPos                     identifier-                    fieldStack             7 -> do                 sizeAndType <- readAndAdvance bufferPos metaDataBuf                 listSize <-@@ -354,21 +347,19 @@                         else return $ fromIntegral ((sizeAndType `shiftR` 4) .&. 0x0f)                  let _elemType = toTType sizeAndType-                columnOrders <- replicateM listSize (readColumnOrder metaDataBuf bufferPos 0 [])+                columnOrders <- replicateM listSize (readColumnOrder metaDataBuf bufferPos 0)                 readFileMetaData                     (metadata{columnOrders = columnOrders})                     metaDataBuf                     bufferPos                     identifier-                    fieldStack             8 -> do-                encryptionAlgorithm <- readEncryptionAlgorithm metaDataBuf bufferPos 0 []+                encryptionAlgorithm <- readEncryptionAlgorithm metaDataBuf bufferPos 0                 readFileMetaData                     (metadata{encryptionAlgorithm = encryptionAlgorithm})                     metaDataBuf                     bufferPos                     identifier-                    fieldStack             9 -> do                 footerSigningKeyMetadata <- readByteString metaDataBuf bufferPos                 readFileMetaData@@ -376,7 +367,6 @@                     metaDataBuf                     bufferPos                     identifier-                    fieldStack             n -> return $ error $ "UNIMPLEMENTED " ++ show n  readSchemaElement ::@@ -384,13 +374,11 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO SchemaElement-readSchemaElement schemaElement buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readSchemaElement schemaElement buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return schemaElement-        Just (STOP, _) -> return schemaElement         Just (elemType, identifier) -> case identifier of             1 -> do                 schemaElemType <- toIntegralType <$> readInt32FromBuffer buf pos@@ -399,7 +387,6 @@                     buf                     pos                     identifier-                    fieldStack             2 -> do                 typeLength <- readInt32FromBuffer buf pos                 readSchemaElement@@ -407,7 +394,6 @@                     buf                     pos                     identifier-                    fieldStack             3 -> do                 fieldRepetitionType <- readInt32FromBuffer buf pos                 readSchemaElement@@ -415,11 +401,10 @@                     buf                     pos                     identifier-                    fieldStack             4 -> do                 nameSize <- readVarIntFromBuffer @Int buf pos                 if nameSize <= 0-                    then readSchemaElement schemaElement buf pos identifier fieldStack+                    then readSchemaElement schemaElement buf pos identifier                     else do                         contents <- replicateM nameSize (readAndAdvance pos buf)                         readSchemaElement@@ -427,7 +412,6 @@                             buf                             pos                             identifier-                            fieldStack             5 -> do                 numChildren <- readInt32FromBuffer buf pos                 readSchemaElement@@ -435,7 +419,6 @@                     buf                     pos                     identifier-                    fieldStack             6 -> do                 convertedType <- readInt32FromBuffer buf pos                 readSchemaElement@@ -443,10 +426,9 @@                     buf                     pos                     identifier-                    fieldStack             7 -> do                 scale <- readInt32FromBuffer buf pos-                readSchemaElement (schemaElement{scale = scale}) buf pos identifier fieldStack+                readSchemaElement (schemaElement{scale = scale}) buf pos identifier             8 -> do                 precision <- readInt32FromBuffer buf pos                 readSchemaElement@@ -454,7 +436,6 @@                     buf                     pos                     identifier-                    fieldStack             9 -> do                 fieldId <- readInt32FromBuffer buf pos                 readSchemaElement@@ -462,21 +443,19 @@                     buf                     pos                     identifier-                    fieldStack             10 -> do-                logicalType <- readLogicalType buf pos 0 []+                logicalType <- readLogicalType LOGICAL_TYPE_UNKNOWN buf pos 0                 readSchemaElement                     (schemaElement{logicalType = logicalType})                     buf                     pos                     identifier-                    fieldStack-            _ -> error "Uknown schema element"+            n -> error ("Uknown schema element: " ++ show n)  readRowGroup ::-    RowGroup -> BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO RowGroup-readRowGroup r buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+    RowGroup -> BS.ByteString -> IORef Int -> Int16 -> IO RowGroup+readRowGroup r buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return r         Just (elemType, identifier) -> case identifier of@@ -488,18 +467,18 @@                         else return $ fromIntegral ((sizeAndType `shiftR` 4) .&. 0x0f)                 let _elemType = toTType sizeAndType                 columnChunks <--                    replicateM listSize (readColumnChunk emptyColumnChunk buf pos 0 [])-                readRowGroup (r{rowGroupColumns = columnChunks}) buf pos identifier fieldStack+                    replicateM listSize (readColumnChunk emptyColumnChunk buf pos 0)+                readRowGroup (r{rowGroupColumns = columnChunks}) buf pos identifier             2 -> do                 totalBytes <- readIntFromBuffer @Int64 buf pos-                readRowGroup (r{totalByteSize = totalBytes}) buf pos identifier fieldStack+                readRowGroup (r{totalByteSize = totalBytes}) buf pos identifier             3 -> do                 nRows <- readIntFromBuffer @Int64 buf pos-                readRowGroup (r{rowGroupNumRows = nRows}) buf pos identifier fieldStack+                readRowGroup (r{rowGroupNumRows = nRows}) buf pos identifier             4 -> return r             5 -> do                 offset <- readIntFromBuffer @Int64 buf pos-                readRowGroup (r{fileOffset = offset}) buf pos identifier fieldStack+                readRowGroup (r{fileOffset = offset}) buf pos identifier             6 -> do                 compressedSize <- readIntFromBuffer @Int64 buf pos                 readRowGroup@@ -507,16 +486,15 @@                     buf                     pos                     identifier-                    fieldStack             7 -> do                 ordinal <- readIntFromBuffer @Int16 buf pos-                readRowGroup (r{ordinal = ordinal}) buf pos identifier fieldStack+                readRowGroup (r{ordinal = ordinal}) buf pos identifier             _ -> error $ "Unknown row group field: " ++ show identifier  readColumnChunk ::-    ColumnChunk -> BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO ColumnChunk-readColumnChunk c buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+    ColumnChunk -> BS.ByteString -> IORef Int -> Int16 -> IO ColumnChunk+readColumnChunk c buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return c         Just (elemType, identifier) -> case identifier of@@ -529,7 +507,6 @@                     buf                     pos                     identifier-                    fieldStack             2 -> do                 columnChunkMetadataFileOffset <- readIntFromBuffer @Int64 buf pos                 readColumnChunk@@ -537,15 +514,13 @@                     buf                     pos                     identifier-                    fieldStack             3 -> do-                columnMetadata <- readColumnMetadata emptyColumnMetadata buf pos 0 []+                columnMetadata <- readColumnMetadata emptyColumnMetadata buf pos 0                 readColumnChunk                     (c{columnMetaData = columnMetadata})                     buf                     pos                     identifier-                    fieldStack             4 -> do                 columnOffsetIndexOffset <- readIntFromBuffer @Int64 buf pos                 readColumnChunk@@ -553,7 +528,6 @@                     buf                     pos                     identifier-                    fieldStack             5 -> do                 columnOffsetIndexLength <- readInt32FromBuffer buf pos                 readColumnChunk@@ -561,7 +535,6 @@                     buf                     pos                     identifier-                    fieldStack             6 -> do                 columnChunkColumnIndexOffset <- readIntFromBuffer @Int64 buf pos                 readColumnChunk@@ -569,7 +542,6 @@                     buf                     pos                     identifier-                    fieldStack             7 -> do                 columnChunkColumnIndexLength <- readInt32FromBuffer buf pos                 readColumnChunk@@ -577,7 +549,6 @@                     buf                     pos                     identifier-                    fieldStack             _ -> error "Unknown column chunk"  readColumnMetadata ::@@ -585,27 +556,25 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO ColumnMetaData-readColumnMetadata cm buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readColumnMetadata cm buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return cm         Just (elemType, identifier) -> case identifier of             1 -> do                 cType <- parquetTypeFromInt <$> readInt32FromBuffer buf pos-                readColumnMetadata (cm{columnType = cType}) buf pos identifier []+                readColumnMetadata (cm{columnType = cType}) buf pos identifier             2 -> do                 sizeAndType <- readAndAdvance pos buf                 let sizeOnly = fromIntegral ((sizeAndType `shiftR` 4) .&. 0x0f) :: Int                 let _elemType = toTType sizeAndType-                encodings <- replicateM sizeOnly (readParquetEncoding buf pos 0 [])+                encodings <- replicateM sizeOnly (readParquetEncoding buf pos 0)                 readColumnMetadata                     (cm{columnEncodings = encodings})                     buf                     pos                     identifier-                    fieldStack             3 -> do                 sizeAndType <- readAndAdvance pos buf                 let sizeOnly = fromIntegral ((sizeAndType `shiftR` 4) .&. 0x0f) :: Int@@ -616,13 +585,12 @@                     buf                     pos                     identifier-                    fieldStack             4 -> do                 cType <- compressionCodecFromInt <$> readInt32FromBuffer buf pos-                readColumnMetadata (cm{columnCodec = cType}) buf pos identifier []+                readColumnMetadata (cm{columnCodec = cType}) buf pos identifier             5 -> do                 numValues <- readIntFromBuffer @Int64 buf pos-                readColumnMetadata (cm{columnNumValues = numValues}) buf pos identifier []+                readColumnMetadata (cm{columnNumValues = numValues}) buf pos identifier             6 -> do                 columnTotalUncompressedSize <- readIntFromBuffer @Int64 buf pos                 readColumnMetadata@@ -630,7 +598,6 @@                     buf                     pos                     identifier-                    []             7 -> do                 columnTotalCompressedSize <- readIntFromBuffer @Int64 buf pos                 readColumnMetadata@@ -638,19 +605,17 @@                     buf                     pos                     identifier-                    []             8 -> do                 sizeAndType <- readAndAdvance pos buf                 let sizeOnly = fromIntegral ((sizeAndType `shiftR` 4) .&. 0x0f) :: Int                 let _elemType = toTType sizeAndType                 columnKeyValueMetadata <--                    replicateM sizeOnly (readKeyValue emptyKeyValue buf pos 0 [])+                    replicateM sizeOnly (readKeyValue emptyKeyValue buf pos 0)                 readColumnMetadata                     (cm{columnKeyValueMetadata = columnKeyValueMetadata})                     buf                     pos                     identifier-                    fieldStack             9 -> do                 columnDataPageOffset <- readIntFromBuffer @Int64 buf pos                 readColumnMetadata@@ -658,7 +623,6 @@                     buf                     pos                     identifier-                    []             10 -> do                 columnIndexPageOffset <- readIntFromBuffer @Int64 buf pos                 readColumnMetadata@@ -666,7 +630,6 @@                     buf                     pos                     identifier-                    []             11 -> do                 columnDictionaryPageOffset <- readIntFromBuffer @Int64 buf pos                 readColumnMetadata@@ -674,22 +637,20 @@                     buf                     pos                     identifier-                    []             12 -> do-                stats <- readStatistics emptyColumnStatistics buf pos 0 []-                readColumnMetadata (cm{columnStatistics = stats}) buf pos identifier fieldStack+                stats <- readStatistics emptyColumnStatistics buf pos 0+                readColumnMetadata (cm{columnStatistics = stats}) buf pos identifier             13 -> do                 sizeAndType <- readAndAdvance pos buf                 let sizeOnly = fromIntegral ((sizeAndType `shiftR` 4) .&. 0x0f) :: Int                 let _elemType = toTType sizeAndType                 pageEncodingStats <--                    replicateM sizeOnly (readPageEncodingStats emptyPageEncodingStats buf pos 0 [])+                    replicateM sizeOnly (readPageEncodingStats emptyPageEncodingStats buf pos 0)                 readColumnMetadata                     (cm{columnEncodingStats = pageEncodingStats})                     buf                     pos                     identifier-                    fieldStack             14 -> do                 bloomFilterOffset <- readIntFromBuffer @Int64 buf pos                 readColumnMetadata@@ -697,7 +658,6 @@                     buf                     pos                     identifier-                    []             15 -> do                 bloomFilterLength <- readInt32FromBuffer buf pos                 readColumnMetadata@@ -705,22 +665,20 @@                     buf                     pos                     identifier-                    []             16 -> do-                stats <- readSizeStatistics emptySizeStatistics buf pos 0 []+                stats <- readSizeStatistics emptySizeStatistics buf pos 0                 readColumnMetadata                     (cm{columnSizeStatistics = stats})                     buf                     pos                     identifier-                    fieldStack             17 -> return $ error "UNIMPLEMENTED"             _ -> error $ "Unknown column metadata " ++ show identifier  readEncryptionAlgorithm ::-    BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO EncryptionAlgorithm-readEncryptionAlgorithm buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+    BS.ByteString -> IORef Int -> Int16 -> IO EncryptionAlgorithm+readEncryptionAlgorithm buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return ENCRYPTION_ALGORITHM_UNKNOWN         Just (elemType, identifier) -> case identifier of@@ -730,25 +688,24 @@                     buf                     pos                     0-                    []             2 -> do                 readAesGcmCtrV1                     (AesGcmCtrV1{aadPrefix = [], aadFileUnique = [], supplyAadPrefix = False})                     buf                     pos                     0-                    []             n -> return ENCRYPTION_ALGORITHM_UNKNOWN  readColumnOrder ::-    BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO ColumnOrder-readColumnOrder buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+    BS.ByteString -> IORef Int -> Int16 -> IO ColumnOrder+readColumnOrder buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return COLUMN_ORDER_UNKNOWN         Just (elemType, identifier) -> case identifier of             1 -> do-                replicateM_ 2 (readTypeOrder buf pos 0 [])+                -- Read begin struct and stop since this an empty struct.+                replicateM_ 2 (readTypeOrder buf pos 0)                 return TYPE_ORDER             _ -> return COLUMN_ORDER_UNKNOWN @@ -757,16 +714,15 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO EncryptionAlgorithm-readAesGcmCtrV1 v@(AesGcmCtrV1 aadPrefix aadFileUnique supplyAadPrefix) buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readAesGcmCtrV1 v@(AesGcmCtrV1 aadPrefix aadFileUnique supplyAadPrefix) buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return v         Just (elemType, identifier) -> case identifier of             1 -> do                 aadPrefix <- readByteString buf pos-                readAesGcmCtrV1 (v{aadPrefix = aadPrefix}) buf pos lastFieldId fieldStack+                readAesGcmCtrV1 (v{aadPrefix = aadPrefix}) buf pos lastFieldId             2 -> do                 aadFileUnique <- readByteString buf pos                 readAesGcmCtrV1@@ -774,7 +730,6 @@                     buf                     pos                     lastFieldId-                    fieldStack             3 -> do                 supplyAadPrefix <- readAndAdvance pos buf                 readAesGcmCtrV1@@ -782,9 +737,8 @@                     buf                     pos                     lastFieldId-                    fieldStack             _ -> return ENCRYPTION_ALGORITHM_UNKNOWN-readAesGcmCtrV1 _ _ _ _ _ =+readAesGcmCtrV1 _ _ _ _ =     error "readAesGcmCtrV1 called with non AesGcmCtrV1"  readAesGcmV1 ::@@ -792,19 +746,18 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO EncryptionAlgorithm-readAesGcmV1 v@(AesGcmV1 aadPrefix aadFileUnique supplyAadPrefix) buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readAesGcmV1 v@(AesGcmV1 aadPrefix aadFileUnique supplyAadPrefix) buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return v         Just (elemType, identifier) -> case identifier of             1 -> do                 aadPrefix <- readByteString buf pos-                readAesGcmV1 (v{aadPrefix = aadPrefix}) buf pos lastFieldId fieldStack+                readAesGcmV1 (v{aadPrefix = aadPrefix}) buf pos lastFieldId             2 -> do                 aadFileUnique <- readByteString buf pos-                readAesGcmV1 (v{aadFileUnique = aadFileUnique}) buf pos lastFieldId fieldStack+                readAesGcmV1 (v{aadFileUnique = aadFileUnique}) buf pos lastFieldId             3 -> do                 supplyAadPrefix <- readAndAdvance pos buf                 readAesGcmV1@@ -812,35 +765,34 @@                     buf                     pos                     lastFieldId-                    fieldStack             _ -> return ENCRYPTION_ALGORITHM_UNKNOWN-readAesGcmV1 _ _ _ _ _ =+readAesGcmV1 _ _ _ _ =     error "readAesGcmV1 called with non AesGcmV1"  readTypeOrder ::-    BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO ColumnOrder-readTypeOrder buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+    BS.ByteString -> IORef Int -> Int16 -> IO ColumnOrder+readTypeOrder buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return TYPE_ORDER         Just (elemType, identifier) ->             if elemType == STOP                 then return TYPE_ORDER-                else readTypeOrder buf pos identifier fieldStack+                else readTypeOrder buf pos identifier  readKeyValue ::-    KeyValue -> BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO KeyValue-readKeyValue kv buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+    KeyValue -> BS.ByteString -> IORef Int -> Int16 -> IO KeyValue+readKeyValue kv buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return kv         Just (elemType, identifier) -> case identifier of             1 -> do                 k <- readString buf pos-                readKeyValue (kv{key = k}) buf pos identifier fieldStack+                readKeyValue (kv{key = k}) buf pos identifier             2 -> do                 v <- readString buf pos-                readKeyValue (kv{value = v}) buf pos identifier fieldStack+                readKeyValue (kv{value = v}) buf pos identifier             _ -> error "Unknown kv"  readPageEncodingStats ::@@ -848,19 +800,18 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO PageEncodingStats-readPageEncodingStats pes buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readPageEncodingStats pes buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return pes         Just (elemType, identifier) -> case identifier of             1 -> do                 pType <- pageTypeFromInt <$> readInt32FromBuffer buf pos-                readPageEncodingStats (pes{pageEncodingPageType = pType}) buf pos identifier []+                readPageEncodingStats (pes{pageEncodingPageType = pType}) buf pos identifier             2 -> do                 pEnc <- parquetEncodingFromInt <$> readInt32FromBuffer buf pos-                readPageEncodingStats (pes{pageEncoding = pEnc}) buf pos identifier []+                readPageEncodingStats (pes{pageEncoding = pEnc}) buf pos identifier             3 -> do                 encodedCount <- readInt32FromBuffer buf pos                 readPageEncodingStats@@ -868,34 +819,32 @@                     buf                     pos                     identifier-                    []             _ -> error "Unknown page encoding stats"  readParquetEncoding ::-    BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO ParquetEncoding-readParquetEncoding buf pos lastFieldId fieldStack = parquetEncodingFromInt <$> readInt32FromBuffer buf pos+    BS.ByteString -> IORef Int -> Int16 -> IO ParquetEncoding+readParquetEncoding buf pos lastFieldId = parquetEncodingFromInt <$> readInt32FromBuffer buf pos  readStatistics ::     ColumnStatistics ->     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO ColumnStatistics-readStatistics cs buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readStatistics cs buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return cs         Just (elemType, identifier) -> case identifier of             1 -> do                 maxInBytes <- readByteString buf pos-                readStatistics (cs{columnMax = maxInBytes}) buf pos identifier fieldStack+                readStatistics (cs{columnMax = maxInBytes}) buf pos identifier             2 -> do                 minInBytes <- readByteString buf pos-                readStatistics (cs{columnMin = minInBytes}) buf pos identifier fieldStack+                readStatistics (cs{columnMin = minInBytes}) buf pos identifier             3 -> do                 nullCount <- readIntFromBuffer @Int64 buf pos-                readStatistics (cs{columnNullCount = nullCount}) buf pos identifier fieldStack+                readStatistics (cs{columnNullCount = nullCount}) buf pos identifier             4 -> do                 distinctCount <- readIntFromBuffer @Int64 buf pos                 readStatistics@@ -903,13 +852,12 @@                     buf                     pos                     identifier-                    fieldStack             5 -> do                 maxInBytes <- readByteString buf pos-                readStatistics (cs{columnMaxValue = maxInBytes}) buf pos identifier fieldStack+                readStatistics (cs{columnMaxValue = maxInBytes}) buf pos identifier             6 -> do                 minInBytes <- readByteString buf pos-                readStatistics (cs{columnMinValue = minInBytes}) buf pos identifier fieldStack+                readStatistics (cs{columnMinValue = minInBytes}) buf pos identifier             7 -> do                 isMaxValueExact <- readAndAdvance pos buf                 readStatistics@@ -917,7 +865,6 @@                     buf                     pos                     identifier-                    fieldStack             8 -> do                 isMinValueExact <- readAndAdvance pos buf                 readStatistics@@ -925,7 +872,6 @@                     buf                     pos                     identifier-                    fieldStack             _ -> error "Unknown statistics"  readSizeStatistics ::@@ -933,10 +879,9 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO SizeStatistics-readSizeStatistics ss buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readSizeStatistics ss buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return ss         Just (elemType, identifier) -> case identifier of@@ -947,7 +892,6 @@                     buf                     pos                     identifier-                    fieldStack             2 -> do                 sizeAndType <- readAndAdvance pos buf                 let sizeOnly = fromIntegral ((sizeAndType `shiftR` 4) .&. 0x0f) :: Int@@ -959,7 +903,6 @@                     buf                     pos                     identifier-                    fieldStack             3 -> do                 sizeAndType <- readAndAdvance pos buf                 let sizeOnly = fromIntegral ((sizeAndType `shiftR` 4) .&. 0x0f) :: Int@@ -971,7 +914,6 @@                     buf                     pos                     identifier-                    fieldStack             _ -> error "Unknown size statistics"  footerSize :: Int@@ -990,68 +932,63 @@     | otherwise = error ("Unknown type in schema: " ++ show n)  readLogicalType ::-    BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO LogicalType-readLogicalType buf pos lastFieldId fieldStack = do-    t <- readAndAdvance pos buf-    if t .&. 0x0f == 0-        then return LOGICAL_TYPE_UNKNOWN-        else do-            let modifier = fromIntegral ((t .&. 0xf0) `shiftR` 4) :: Int16-            identifier <--                if modifier == 0-                    then readIntFromBuffer @Int16 buf pos-                    else return (lastFieldId + modifier)-            let _elemType = toTType (t .&. 0x0f)-            case identifier of-                1 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return STRING_TYPE-                2 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return MAP_TYPE-                3 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return LIST_TYPE-                4 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return ENUM_TYPE-                5 -> do-                    readDecimalType 0 0 buf pos 0 []-                6 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return DATE_TYPE-                7 -> do-                    readTimeType False MILLISECONDS buf pos 0 []-                8 -> do-                    readTimestampType False MILLISECONDS buf pos 0 []-                -- Apparently reserved for interval types-                9 -> return LOGICAL_TYPE_UNKNOWN-                10 -> do-                    intType <- readIntType 0 False buf pos 0 []-                    _ <- readField buf pos 0 []-                    pure intType-                11 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return LOGICAL_TYPE_UNKNOWN-                12 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return JSON_TYPE-                13 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return BSON_TYPE-                14 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return UUID_TYPE-                15 -> do-                    replicateM_ 2 (readField buf pos 0 [])-                    return FLOAT16_TYPE-                16 -> do-                    return VariantType{specificationVersion = 1}-                17 -> do-                    return GeometryType{crs = ""}-                18 -> do-                    return GeographyType{crs = "", algorithm = SPHERICAL}-                _ -> return LOGICAL_TYPE_UNKNOWN+    LogicalType -> BS.ByteString -> IORef Int -> Int16 -> IO LogicalType+readLogicalType logicalType buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId+    case fieldContents of+        Nothing -> pure logicalType+        Just (elemType, identifier) -> case identifier of+            1 -> do+                -- This is an empty enum and is read as a field.+                _ <- readField buf pos 0+                readLogicalType STRING_TYPE buf pos identifier+            2 -> do+                _ <- readField buf pos 0+                readLogicalType MAP_TYPE buf pos identifier+            3 -> do+                _ <- readField buf pos 0+                readLogicalType LIST_TYPE buf pos identifier+            4 -> do+                _ <- readField buf pos 0+                readLogicalType ENUM_TYPE buf pos identifier+            5 -> do+                decimal <- readDecimalType 0 0 buf pos 0+                readLogicalType decimal buf pos identifier+            6 -> do+                _ <- readField buf pos 0+                readLogicalType DATE_TYPE buf pos identifier+            7 -> do+                time <- readTimeType False MILLISECONDS buf pos 0+                readLogicalType time buf pos identifier+            8 -> do+                timestamp <- readTimestampType False MILLISECONDS buf pos 0+                readLogicalType timestamp buf pos identifier+            -- Apparently reserved for interval types+            9 -> do+                _ <- readField buf pos 0+                readLogicalType LOGICAL_TYPE_UNKNOWN buf pos identifier+            10 -> do+                intType <- readIntType 0 False buf pos 0+                readLogicalType intType buf pos identifier+            11 -> do+                _ <- readField buf pos 0+                readLogicalType LOGICAL_TYPE_UNKNOWN buf pos identifier+            12 -> do+                _ <- readField buf pos 0+                readLogicalType JSON_TYPE buf pos identifier+            13 -> do+                _ <- readField buf pos 0+                readLogicalType BSON_TYPE buf pos identifier+            14 -> do+                _ <- readField buf pos 0+                readLogicalType UUID_TYPE buf pos identifier+            15 -> do+                _ <- readField buf pos 0+                readLogicalType FLOAT16_TYPE buf pos identifier+            16 -> error "Variant fields are unsupported"+            17 -> error "Geometry fields are unsupported"+            18 -> error "Geography fields are unsupported"+            n -> error $ "Unknown logical type field: " ++ show n  readIntType ::     Int8 ->@@ -1059,9 +996,8 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO LogicalType-readIntType bitWidth intIsSigned buf pos lastFieldId fieldStack = do+readIntType bitWidth intIsSigned buf pos lastFieldId = do     t <- readAndAdvance pos buf     if t .&. 0x0f == 0         then return (IntType bitWidth intIsSigned)@@ -1075,10 +1011,10 @@             case identifier of                 1 -> do                     bitWidth' <- readAndAdvance pos buf-                    readIntType (fromIntegral bitWidth') intIsSigned buf pos identifier fieldStack+                    readIntType (fromIntegral bitWidth') intIsSigned buf pos identifier                 2 -> do                     let intIsSigned' = (t .&. 0x0f) == compactBooleanTrue-                    readIntType bitWidth intIsSigned' buf pos identifier fieldStack+                    readIntType bitWidth intIsSigned' buf pos identifier                 _ -> error $ "UNKNOWN field ID for IntType: " ++ show identifier  readDecimalType ::@@ -1087,19 +1023,18 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO LogicalType-readDecimalType precision scale buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readDecimalType precision scale buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return (DecimalType precision scale)         Just (elemType, identifier) -> case identifier of             1 -> do                 scale' <- readInt32FromBuffer buf pos-                readDecimalType precision scale' buf pos lastFieldId fieldStack+                readDecimalType precision scale' buf pos lastFieldId             2 -> do                 precision' <- readInt32FromBuffer buf pos-                readDecimalType precision' scale buf pos lastFieldId fieldStack+                readDecimalType precision' scale buf pos lastFieldId             _ -> error $ "UNKNOWN field ID for DecimalType" ++ show identifier  readTimeType ::@@ -1108,20 +1043,19 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO LogicalType-readTimeType isAdjustedToUTC unit buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readTimeType isAdjustedToUTC unit buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return (TimeType isAdjustedToUTC unit)         Just (elemType, identifier) -> case identifier of             1 -> do                 -- TODO: Check for empty                 isAdjustedToUTC' <- (== compactBooleanTrue) <$> readAndAdvance pos buf-                readTimeType isAdjustedToUTC' unit buf pos lastFieldId fieldStack+                readTimeType isAdjustedToUTC' unit buf pos lastFieldId             2 -> do-                unit' <- readUnit buf pos 0 []-                readTimeType isAdjustedToUTC unit' buf pos lastFieldId fieldStack+                unit' <- readUnit TIME_UNIT_UNKNOWN buf pos 0+                readTimeType isAdjustedToUTC unit' buf pos lastFieldId             _ -> error $ "UNKNOWN field ID for TimeType" ++ show identifier  readTimestampType ::@@ -1130,35 +1064,32 @@     BS.ByteString ->     IORef Int ->     Int16 ->-    [Int16] ->     IO LogicalType-readTimestampType isAdjustedToUTC unit buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readTimestampType isAdjustedToUTC unit buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of         Nothing -> return (TimestampType isAdjustedToUTC unit)         Just (elemType, identifier) -> case identifier of             1 -> do                 -- TODO: Check for empty-                isAdjustedToUTC' <- (== compactBooleanTrue) <$> readAndAdvance pos buf-                readTimestampType isAdjustedToUTC' unit buf pos lastFieldId fieldStack+                isAdjustedToUTC' <- (== compactBooleanTrue) <$> readNoAdvance pos buf+                readTimestampType False unit buf pos lastFieldId             2 -> do-                unit' <- readUnit buf pos 0 []-                readTimestampType isAdjustedToUTC unit' buf pos lastFieldId fieldStack+                _ <- readField buf pos identifier+                unit' <- readUnit TIME_UNIT_UNKNOWN buf pos 0+                readTimestampType isAdjustedToUTC unit' buf pos lastFieldId             _ -> error $ "UNKNOWN field ID for TimestampType" ++ show identifier -readUnit :: BS.ByteString -> IORef Int -> Int16 -> [Int16] -> IO TimeUnit-readUnit buf pos lastFieldId fieldStack = do-    fieldContents <- readField buf pos lastFieldId fieldStack+readUnit :: TimeUnit -> BS.ByteString -> IORef Int -> Int16 -> IO TimeUnit+readUnit unit buf pos lastFieldId = do+    fieldContents <- readField buf pos lastFieldId     case fieldContents of-        Nothing -> return TIME_UNIT_UNKNOWN+        Nothing -> return unit         Just (elemType, identifier) -> case identifier of             1 -> do-                _ <- readField buf pos 0 []-                return MILLISECONDS+                readUnit MILLISECONDS buf pos identifier             2 -> do-                _ <- readField buf pos 0 []-                return MICROSECONDS+                readUnit MICROSECONDS buf pos identifier             3 -> do-                _ <- readField buf pos 0 []-                return NANOSECONDS-            _ -> return TIME_UNIT_UNKNOWN+                readUnit NANOSECONDS buf pos identifier+            n -> error $ "Unknown time unit: " ++ show n
src/DataFrame/Monad.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE ExplicitNamespaces #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-}+{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-}@@ -10,7 +11,7 @@ import DataFrame (DataFrame) import qualified DataFrame as D import DataFrame.Internal.Column (Columnable)-import DataFrame.Internal.Expression (Expr)+import DataFrame.Internal.Expression (Expr (..))  import qualified Data.Text as T @@ -20,31 +21,60 @@ newtype FrameM a = FrameM {runFrameM_ :: DataFrame -> (DataFrame, a)}  instance Functor FrameM where+    fmap :: (a -> b) -> FrameM a -> FrameM b     fmap f (FrameM g) = FrameM $ \df ->         let (df', x) = g df          in (df', f x)  instance Applicative FrameM where     pure x = FrameM (,x)+    (<*>) :: FrameM (a -> b) -> FrameM a -> FrameM b     FrameM ff <*> FrameM fx = FrameM $ \df ->         let (df1, f) = ff df             (df2, x) = fx df1          in (df2, f x)  instance Monad FrameM where+    (>>=) :: FrameM a -> (a -> FrameM b) -> FrameM b     FrameM g >>= f = FrameM $ \df ->         let (df1, x) = g df             FrameM h = f x          in h df1 +modifyM :: (DataFrame -> DataFrame) -> FrameM ()+modifyM f = FrameM $ \df -> (f df, ())++inspectM :: (DataFrame -> b) -> FrameM b+inspectM f = FrameM $ \df -> (df, f df)+ deriveM :: (Columnable a) => T.Text -> Expr a -> FrameM (Expr a) deriveM name expr = FrameM $ \df ->     let df' = D.derive name expr df-     in (df', expr) -- or (df', F.col @a name)+     in (df', Col name)  filterWhereM :: Expr Bool -> FrameM ()-filterWhereM p = FrameM $ \df ->-    (D.filterWhere p df, ())+filterWhereM p = modifyM (D.filterWhere p) -runFrameM :: DataFrame -> FrameM a -> DataFrame-runFrameM df action = fst (runFrameM_ action df)+filterJustM :: (Columnable a) => Expr (Maybe a) -> FrameM (Expr a)+filterJustM (Col name) = FrameM $ \df ->+    let df' = D.filterJust name df+     in (df', Col name)+filterJustM expr =+    error $ "Cannot filter on compound expression: " ++ show expr++imputeM :: (Columnable a) => Expr (Maybe a) -> a -> FrameM (Expr a)+imputeM expr@(Col name) value = FrameM $ \df ->+    let df' = D.impute expr value df+     in (df', Col name)+imputeM expr _ = error $ "Cannot impute on compound expression: " ++ show expr++runFrameM :: DataFrame -> FrameM a -> (a, DataFrame)+runFrameM df (FrameM action) =+    let (df', a) = action df+     in (a, df')++evalFrameM :: DataFrame -> FrameM a -> a+evalFrameM df m = fst (runFrameM df m)++execFrameM :: DataFrame -> FrameM a -> DataFrame+execFrameM df m = snd (runFrameM df m)
src/DataFrame/Operations/Core.hs view
@@ -31,8 +31,17 @@     expandColumn,     fromList,     fromVector,+    toDoubleVector,+    toFloatVector,+    toIntVector,+    toUnboxedVector,  )-import DataFrame.Internal.DataFrame (DataFrame (..), empty, getColumn)+import DataFrame.Internal.DataFrame (+    DataFrame (..),+    empty,+    getColumn,+    unsafeGetColumn,+ ) import DataFrame.Internal.Expression import DataFrame.Internal.Parsing (isNullish) import DataFrame.Internal.Row (Any, mkColumnFromRow)@@ -749,3 +758,169 @@ -} fold :: (a -> DataFrame -> DataFrame) -> [a] -> DataFrame -> DataFrame fold f xs acc = L.foldl' (flip f) acc xs++{- | Returns a dataframe as a two dimensional vector of floats.++Converts all columns in the dataframe to float vectors and transposes them+into a row-major matrix representation.++This is useful for handing data over into ML systems.++Returns 'Left' with an error if any column cannot be converted to floats.+-}+toFloatMatrix ::+    DataFrame -> Either DataFrameException (V.Vector (VU.Vector Float))+toFloatMatrix df = case V.foldl'+    (\acc c -> V.snoc <$> acc <*> toFloatVector c)+    (Right V.empty :: Either DataFrameException (V.Vector (VU.Vector Float)))+    (columns df) of+    Left e -> Left e+    Right m ->+        pure $+            V.generate+                (fst (dataframeDimensions df))+                ( \i ->+                    foldl+                        (\acc j -> acc `VU.snoc` ((m VG.! j) VG.! i))+                        VU.empty+                        [0 .. (V.length m - 1)]+                )++{- | Returns a dataframe as a two dimensional vector of doubles.++Converts all columns in the dataframe to double vectors and transposes them+into a row-major matrix representation.++This is useful for handing data over into ML systems.++Returns 'Left' with an error if any column cannot be converted to doubles.+-}+toDoubleMatrix ::+    DataFrame -> Either DataFrameException (V.Vector (VU.Vector Double))+toDoubleMatrix df = case V.foldl'+    (\acc c -> V.snoc <$> acc <*> toDoubleVector c)+    (Right V.empty :: Either DataFrameException (V.Vector (VU.Vector Double)))+    (columns df) of+    Left e -> Left e+    Right m ->+        pure $+            V.generate+                (fst (dataframeDimensions df))+                ( \i ->+                    foldl+                        (\acc j -> acc `VU.snoc` ((m VG.! j) VG.! i))+                        VU.empty+                        [0 .. (V.length m - 1)]+                )++{- | Returns a dataframe as a two dimensional vector of ints.++Converts all columns in the dataframe to int vectors and transposes them+into a row-major matrix representation.++This is useful for handing data over into ML systems.++Returns 'Left' with an error if any column cannot be converted to ints.+-}+toIntMatrix :: DataFrame -> Either DataFrameException (V.Vector (VU.Vector Int))+toIntMatrix df = case V.foldl'+    (\acc c -> V.snoc <$> acc <*> toIntVector c)+    (Right V.empty :: Either DataFrameException (V.Vector (VU.Vector Int)))+    (columns df) of+    Left e -> Left e+    Right m ->+        pure $+            V.generate+                (fst (dataframeDimensions df))+                ( \i ->+                    foldl+                        (\acc j -> acc `VU.snoc` ((m VG.! j) VG.! i))+                        VU.empty+                        [0 .. (V.length m - 1)]+                )++{- | Get a specific column as a vector.++You must specify the type via type applications.++==== __Examples__++>>> columnAsVector @Int "age" df+[25, 30, 35, ...]++>>> columnAsVector @Text "name" df+["Alice", "Bob", "Charlie", ...]++==== __Throws__++* 'error' - if the column type doesn't match the requested type+-}+columnAsVector :: forall a. (Columnable a) => Expr a -> DataFrame -> V.Vector a+columnAsVector (Col name) df = case unsafeGetColumn name df of+    (BoxedColumn (col :: V.Vector b)) -> case testEquality (typeRep @a) (typeRep @b) of+        Nothing -> error "Type error"+        Just Refl -> col+    (OptionalColumn (col :: V.Vector b)) -> case testEquality (typeRep @a) (typeRep @b) of+        Nothing -> error "Type error"+        Just Refl -> col+    (UnboxedColumn (col :: VU.Vector b)) -> case testEquality (typeRep @a) (typeRep @b) of+        Nothing -> error "Type error"+        Just Refl -> VG.convert col+columnAsVector _ _ = error "UNIMPLEMENTED"++{- | Retrieves a column as an unboxed vector of 'Int' values.++Returns 'Left' with a 'DataFrameException' if the column cannot be converted to ints.+This may occur if the column contains non-numeric data or values outside the 'Int' range.+-}+columnAsIntVector ::+    Expr Int -> DataFrame -> Either DataFrameException (VU.Vector Int)+columnAsIntVector (Col name) df = toIntVector (unsafeGetColumn name df)+columnAsIntVector _ _ = error "UNIMPLEMENTED"++{- | Retrieves a column as an unboxed vector of 'Double' values.++Returns 'Left' with a 'DataFrameException' if the column cannot be converted to doubles.+This may occur if the column contains non-numeric data.+-}+columnAsDoubleVector ::+    Expr Double -> DataFrame -> Either DataFrameException (VU.Vector Double)+columnAsDoubleVector (Col name) df = toDoubleVector (unsafeGetColumn name df)+columnAsDoubleVector _ _ = error "UNIMPLEMENTED"++{- | Retrieves a column as an unboxed vector of 'Float' values.++Returns 'Left' with a 'DataFrameException' if the column cannot be converted to floats.+This may occur if the column contains non-numeric data.+-}+columnAsFloatVector ::+    Expr Float -> DataFrame -> Either DataFrameException (VU.Vector Float)+columnAsFloatVector (Col name) df = toFloatVector (unsafeGetColumn name df)+columnAsFloatVector _ _ = error "UNIMPLEMENTED"++columnAsUnboxedVector ::+    forall a.+    (Columnable a, VU.Unbox a) =>+    Expr a -> DataFrame -> Either DataFrameException (VU.Vector a)+columnAsUnboxedVector (Col name) df = toUnboxedVector @a (unsafeGetColumn name df)+columnAsUnboxedVector _ _ = error "UNIMPLEMENTED"++{- | Get a specific column as a list.++You must specify the type via type applications.++==== __Examples__++>>> columnAsList @Int "age" df+[25, 30, 35, ...]++>>> columnAsList @Text "name" df+["Alice", "Bob", "Charlie", ...]++==== __Throws__++* 'error' - if the column type doesn't match the requested type+-}+columnAsList :: forall a. (Columnable a) => Expr a -> DataFrame -> [a]+columnAsList expr@(Col name) df = V.toList (columnAsVector expr df)+columnAsList _ _ = error "UNIMPLEMENTED"
src/DataFrame/Operations/Statistics.hs view
@@ -25,8 +25,6 @@ import DataFrame.Internal.Column import DataFrame.Internal.DataFrame (     DataFrame (..),-    columnAsUnboxedVector,-    columnAsVector,     empty,     getColumn,  )@@ -89,7 +87,7 @@ -- | Calculates the mean of a given column as a standalone value. mean ::     forall a. (Columnable a, Real a, VU.Unbox a) => Expr a -> DataFrame -> Double-mean (Col name) df = case columnAsUnboxedVector @a name df of+mean (Col name) df = case columnAsUnboxedVector (Col @a name) df of     Right xs -> mean' xs     Left e -> throw e mean expr df = case interpret df expr of@@ -100,7 +98,7 @@  meanMaybe ::     forall a. (Columnable a, Real a) => Expr (Maybe a) -> DataFrame -> Double-meanMaybe (Col name) df = (mean' . optionalToDoubleVector) (columnAsVector @(Maybe a) name df)+meanMaybe (Col name) df = (mean' . optionalToDoubleVector) (columnAsVector (Col @(Maybe a) name) df) meanMaybe expr df = case interpret @(Maybe a) df expr of     Left e -> throw e     Right (TColumn col) -> case toVector @(Maybe a) col of@@ -110,7 +108,7 @@ -- | Calculates the median of a given column as a standalone value. median ::     forall a. (Columnable a, Real a, VU.Unbox a) => Expr a -> DataFrame -> Double-median (Col name) df = case columnAsUnboxedVector @a name df of+median (Col name) df = case columnAsUnboxedVector (Col @a name) df of     Right xs -> median' xs     Left e -> throw e median expr df = case interpret df expr of@@ -122,7 +120,7 @@ -- | Calculates the standard deviation of a given column as a standalone value. standardDeviation ::     forall a. (Columnable a, Real a, VU.Unbox a) => Expr a -> DataFrame -> Double-standardDeviation (Col name) df = case columnAsUnboxedVector @a name df of+standardDeviation (Col name) df = case columnAsUnboxedVector (Col @a name) df of     Right xs -> (sqrt . variance') xs     Left e -> throw e standardDeviation expr df = case interpret df expr of@@ -134,7 +132,7 @@ -- | Calculates the skewness of a given column as a standalone value. skewness ::     forall a. (Columnable a, Real a, VU.Unbox a) => Expr a -> DataFrame -> Double-skewness (Col name) df = case columnAsUnboxedVector @a name df of+skewness (Col name) df = case columnAsUnboxedVector (Col @a name) df of     Right xs -> skewness' xs     Left e -> throw e skewness expr df = case interpret df expr of@@ -146,7 +144,7 @@ -- | Calculates the variance of a given column as a standalone value. variance ::     forall a. (Columnable a, Real a, VU.Unbox a) => Expr a -> DataFrame -> Double-variance (Col name) df = case columnAsUnboxedVector @a name df of+variance (Col name) df = case columnAsUnboxedVector (Col @a name) df of     Right xs -> variance' xs     Left e -> throw e variance expr df = case interpret df expr of@@ -158,7 +156,7 @@ -- | Calculates the inter-quartile range of a given column as a standalone value. interQuartileRange ::     forall a. (Columnable a, Real a, VU.Unbox a) => Expr a -> DataFrame -> Double-interQuartileRange (Col name) df = case columnAsUnboxedVector @a name df of+interQuartileRange (Col name) df = case columnAsUnboxedVector (Col @a name) df of     Right xs -> interQuartileRange' xs     Left e -> throw e interQuartileRange expr df = case interpret df expr of
src/DataFrame/Synthesis.hs view
@@ -22,11 +22,10 @@     Expr (..),     eSize,     interpret,-    replaceExpr,  ) import DataFrame.Internal.Statistics import qualified DataFrame.Operations.Statistics as Stats-import DataFrame.Operations.Subset (exclude, select)+import DataFrame.Operations.Subset (exclude)  import Control.Exception (throw) import Data.Containers.ListUtils@@ -40,7 +39,6 @@ import qualified Data.Vector.Unboxed as VU import DataFrame.Functions ((.&&), (.<=), (.>), (.||)) import qualified DataFrame.Operations.Core as D-import qualified DataFrame.Operations.Transformations as D import Debug.Trace (trace) import Type.Reflection (typeRep) @@ -80,6 +78,7 @@         existingPrograms             ++ [ transform p                | p <- ps ++ vars+               , Prelude.not (isConditional p)                , transform <-                     [ sqrt                     , abs@@ -93,20 +92,30 @@                ]             ++ [ F.pow p i                | p <- existingPrograms+               , Prelude.not (isConditional p)                , i <- [2 .. 6]                ]             ++ [ p + q                | (i, p) <- zip [0 ..] existingPrograms                , (j, q) <- zip [0 ..] existingPrograms                , Prelude.not (isLiteral p && isLiteral q)+               , Prelude.not (isConditional p || isConditional q)                , i >= j                ]+            ++ [ p - q+               | (i, p) <- zip [0 ..] existingPrograms+               , (j, q) <- zip [0 ..] existingPrograms+               , Prelude.not (isLiteral p && isLiteral q)+               , Prelude.not (isConditional p || isConditional q)+               , i /= j+               ]             ++ ( if includeConds                     then                         [ F.min p q                         | (i, p) <- zip [0 ..] existingPrograms                         , (j, q) <- zip [0 ..] existingPrograms                         , Prelude.not (isLiteral p && isLiteral q)+                        , Prelude.not (isConditional p || isConditional q)                         , p /= q                         , i > j                         ]@@ -114,6 +123,7 @@                                | (i, p) <- zip [0 ..] existingPrograms                                , (j, q) <- zip [0 ..] existingPrograms                                , Prelude.not (isLiteral p && isLiteral q)+                               , Prelude.not (isConditional p || isConditional q)                                , p /= q                                , i > j                                ]@@ -121,26 +131,23 @@                                | cond <- conds                                , r <- existingPrograms                                , s <- existingPrograms+                               , Prelude.not (isConditional r || isConditional s)                                , r /= s                                ]                     else []                )-            ++ [ p - q-               | (i, p) <- zip [0 ..] existingPrograms-               , (j, q) <- zip [0 ..] existingPrograms-               , Prelude.not (isLiteral p && isLiteral q)-               , i /= j-               ]             ++ [ p * q                | (i, p) <- zip [0 ..] existingPrograms                , (j, q) <- zip [0 ..] existingPrograms                , Prelude.not (isLiteral p && isLiteral q)+               , Prelude.not (isConditional p || isConditional q)                , i >= j                ]             ++ [ p / q                | p <- existingPrograms                , q <- existingPrograms                , Prelude.not (isLiteral p && isLiteral q)+               , Prelude.not (isConditional p || isConditional q)                , p /= q                ] @@ -148,6 +155,10 @@ isLiteral (Lit _) = True isLiteral _ = False +isConditional :: Expr a -> Bool+isConditional (If{}) = True+isConditional _ = False+ deduplicate ::     forall a.     (Columnable a) =>@@ -289,34 +300,12 @@         t = case interpret df (Col target) of             Left e -> throw e             Right v -> v+        cfg = BeamConfig d b MeanSquaredError True+        constants = percentiles df' ++ [Lit 10, Lit 1, Lit 0.1, Lit targetMean]      in-        case beamSearch-            df'-            ( BeamConfig-                d-                b-                MutualInformation-                False-            )-            t-            (percentiles df')-            []-            [] of+        case beamSearch df' cfg t constants [] [] of             Nothing -> Left "No programs found"-            Just p ->-                trace (show p) $-                    let-                     in case beamSearch-                            ( D.derive "_generated_regression_feature_" p df-                                & select ["_generated_regression_feature_"]-                            )-                            (BeamConfig d b MeanSquaredError False)-                            t-                            (percentiles df' ++ [Lit targetMean, Lit 10])-                            []-                            [Col "_generated_regression_feature_"] of-                            Nothing -> Left "Could not find coefficients"-                            Just p' -> Right (replaceExpr p (Col @Double "_generated_regression_feature_") p')+            Just p -> Right p  data LossFunction     = PearsonCorrelation@@ -375,7 +364,7 @@             (generatePrograms (includeConditionals cfg) conditions vars constants ps)   where     vars = map Col names-    conditions = generateConditions outputs conds (vars ++ constants ++ ps) df+    conditions = generateConditions outputs conds vars df     ps = pickTopN df outputs cfg $ deduplicate df programs     names = (map fst . L.sortBy (compare `on` snd) . M.toList . columnIndices) df 
tests/Functions.hs view
@@ -6,9 +6,11 @@ import qualified DataFrame as D import DataFrame.Functions (     sanitize,+    (.>),  ) import qualified DataFrame.Functions as F import qualified DataFrame.Internal.Column as DI+import DataFrame.Internal.Expression import Test.HUnit  -- Test cases for the sanitize function@@ -79,8 +81,48 @@             (D.derive "sum" (F.sum (F.col @Int "A")) df)         ) +testGtTwoLitsRewriteAsLit :: Test+testGtTwoLitsRewriteAsLit =+    TestCase+        ( assertEqual+            "Two lits rewrite as one"+            (Lit True)+            (Lit (5 :: Int) .> Lit 4)+        )++testGtLeftLitRewriteAsUnary :: Test+testGtLeftLitRewriteAsUnary =+    TestCase+        ( assertEqual+            "Two lits rewrite as single literal"+            (UnaryOp "gt 5" ((5 :: Int) >) (Col "x"))+            (Lit (5 :: Int) .> Col "x")+        )++testGtRightLitRewriteAsUnary :: Test+testGtRightLitRewriteAsUnary =+    TestCase+        ( assertEqual+            "Two lits rewrite as unary op"+            (UnaryOp "gt 5" ((5 :: Int) >) (Col "x"))+            (Lit (5 :: Int) .> Col "x")+        )++testGtNoLitWriteAsBinary :: Test+testGtNoLitWriteAsBinary =+    TestCase+        ( assertEqual+            "Two lits rewrite as unary op"+            (BinaryOp "gt" (>) (Col @Int "x") (Col "y"))+            (Col @Int "x" .> Col "y")+        )+ tests :: [Test] tests =     [ TestLabel "sanitizeIdentifiers" sanitizeIdentifiers     , TestLabel "testSum" testSum+    , TestLabel "testGtTwoLitRewrite" testGtTwoLitsRewriteAsLit+    , TestLabel "testGtLeftLit" testGtLeftLitRewriteAsUnary+    , TestLabel "testGtRightLit" testGtRightLitRewriteAsUnary+    , TestLabel "testGtNoLit" testGtNoLitWriteAsBinary     ]