úÎ!5~3b%      !"#$None 7DHVXbe2^box-csvJType of header rows. Note the modern propensity for multiple header rows.box-csvcsv file configurationbox-csvfile name stembox-csv file suffix box-csv directory box-csvfield separator box-csvnature of header row(s) box-csvdefault csv file detailsdefaultCsvConfig|CsvConfig {name = "time_series_covid19_deaths_global_narrow", suffix = ".csv", dir = "./other", fsep = ',', header = HasHXL}test data from Bhttps://data.humdata.org/dataset/novel-coronavirus-2019-ncov-cases box-csvfilepath for the config.file defaultCsvConfig6"./other/time_series_covid19_deaths_global_narrow.csv"box-csv‹A continuation emitter of parsed csv rows from a CsvConfig, returning the original text on failure >>> rowEmitter defaultCsvConfig fields % emit Just (Right ["ProvinceState","CountryRegion",Lat,Long,Date,ValueY,"ISO 3166-1 Alpha 3-Codes","Region Code","Sub-region Code","Intermediate Region Coder"])box-csvcommits printed csv rows>let testConfig = CsvConfig "test" ".csv" "./test" ',' NoHeaderMlet ctest = rowCommitter testConfig (fmap (Text.intercalate "," . fmap show)),ctest `with` (\c -> commit c [[1..10::Int]])True&rowEmitter testConfig ints `with` emit#Just (Right [1,2,3,4,5,6,7,8,9,10])box-csv(Run a parser across all lines of a file.$r1 <- runCsv defaultCsvConfig fields length r142562length [x | (Left x) <- r1]0%take 2 $ drop 2 [x | (Right x) <- r1]•[["","Afghanistan","33.0","65.0","2020-06-29","733","AFG","142","34","\r"],["","Afghanistan","33.0","65.0","2020-06-28","721","AFG","142","34","\r"]]box-csv~Most parsing and building routines implicity assume a character acting as a separator of fields, and newlines separating rows.A.parse (sep ',') ",ok" Done "ok" ()box-csv7an unquoted field Does not consume the separator tokenA.parse (field_ ',') "field,ok"Done ",ok" "field"box-csv.an unquoted field Consume the separator tokenA.parse (field ',') "field,ok"Done "ok" "field"box-csvskipping a field#A.parse (skipField_ ',') "field,ok" Done ",ok" ()box-csvskipping a field"A.parse (skipField ',') "field,ok" Done "ok" ()box-csv int parserA.parse int "234,ok"Done ",ok" 234box-csvint parser, consumes separatorA.parse (int' ',') "234,ok" Done "ok" 234box-csv!double parser, consumes separator"A.parse (double' ',') "234.000,ok"Done "ok" 234.0box-csvDay parser, consumes separator"A.parse (day' ',') "2020-07-01,ok"Done "ok" 2020-07-01box-csv$TimeOfDay parser, consumes separator'A.parse (tod' ',') "23:52:05.221109,ok"Done "ok" 23:52:05.221109box-csv$TimeOfDay parser, consumes separator+A.parse (localtime' ',') "Jun 24 8:24AM,ok"Done "ok" 2020-06-24 08:24:00box-csvHParser for a csv row of [Text]. TODO: deal with potential for an extra '\r'*A.parseOnly (fields ',') "field1,field2\r"Right ["field1","field2\r"]box-csv$parser for a csv row of [Scientific]"A.parseOnly (scis ',') "1,2.2,3.3"Right [1.0,2.2,3.3]box-csv parser for a csv row of [Double]!A.parseOnly (doubles ',') "1,2,3"Right [1.0,2.0,3.0]box-csvparser for a csv row of [Int]A.parseOnly (ints ',') "1,2,3" Right [1,2,3]      &       !"#$%&'()*+$box-csv-0.0.2-6WDeFtr4BJDChfIypM7JrIBox.Csv*attoparsec-0.13.2.4-5dPphue7zS64OdJnfwFzDfData.Attoparsec.TextdoubleHeader HasHeaderHasHXLNoHeader CsvConfignamesuffixdirfsepheaderdefaultCsvConfigfile rowEmitter rowCommitterrunCsvsepfield_field skipField_ skipFieldintint'double'day'tod' localtime'fieldsscisdoublesints $fShowHeader $fEqHeader$fShowCsvConfig$fGenericCsvConfig $fEqCsvConfig box-0.6.0-AEuj2gH0C7VIHoV5DTEF4HBox.Contwith