| CARVIEW |
cassava: A CSV parsing and encoding library
cassava is a library for parsing and encoding RFC 4180
compliant comma-separated values (CSV) data,
which is a textual line-oriented format commonly used for exchanging tabular data.
cassava's API includes support for
Index-based record-conversion
Name-based record-conversion
Typeclass directed conversion of fields and records
Built-in field-conversion instances for standard types
Customizable record-conversion instance derivation via GHC generics
Low-level bytestring builders (see Data.Csv.Builder)
Incremental decoding and encoding API (see Data.Csv.Incremental)
Streaming API for constant-space decoding (see Data.Csv.Streaming)
Moreover, this library is designed to be easy to use; for instance, here's a very simple example of encoding CSV data:
>>>Data.Csv.encode [("John",27),("Jane",28)]"John,27\r\nJane,28\r\n"
Please refer to the documentation in Data.Csv and the included README for more usage examples.
[Skip to Readme]
Modules
[Index] [Quick Jump]
Downloads
- cassava-0.5.4.1.tar.gz [browse] (Cabal source package)
- Package description (as included in the package)
Maintainer's Corner
For package maintainers and hackage trustees
Candidates
| Versions [RSS] | 0.1.0.0, 0.1.0.1, 0.2.0.0, 0.2.1.0, 0.2.1.1, 0.2.1.2, 0.2.2.0, 0.3.0.0, 0.3.0.1, 0.4.0.0, 0.4.1.0, 0.4.2.0, 0.4.2.1, 0.4.2.2, 0.4.2.3, 0.4.2.4, 0.4.3.0, 0.4.3.1, 0.4.4.0, 0.4.5.0, 0.4.5.1, 0.5.0.0, 0.5.1.0, 0.5.2.0, 0.5.3.0, 0.5.3.1, 0.5.3.2, 0.5.4.0, 0.5.4.1 |
|---|---|
| Change log | CHANGES.md |
| Dependencies | array (>=0.5.1.1 && <0.6), attoparsec (>=0.11.3.0 && <0.15), base (>=4.9 && <5), bytestring (>=0.10.8.0 && <0.13), containers (>=0.5.7.1 && <1), deepseq (>=1.4.2.0 && <1.6), hashable (>=1.2.4.0 && <2), Only (>=0.1 && <0.1.1), scientific (>=0.3.4.9 && <0.4), text (>=1.2.2.1 && <2.2), text-short (>=0.1 && <0.2), unordered-containers (>=0.2.7.1 && <0.3), vector (>=0.11.0.0 && <0.14) [details] |
| Tested with | ghc ==9.14.1, ghc ==9.12.2, ghc ==9.10.2, ghc ==9.8.4, ghc ==9.6.7, ghc ==9.4.8, ghc ==9.2.8, ghc ==9.0.2, ghc ==8.10.7, ghc ==8.8.4, ghc ==8.6.5, ghc ==8.4.4, ghc ==8.2.2, ghc ==8.0.2 |
| License | BSD-3-Clause |
| Copyright | (c) 2012 Johan Tibell (c) 2012 Bryan O'Sullivan (c) 2011 MailRank, Inc. |
| Author | Johan Tibell |
| Maintainer | https://github.com/haskell-hvr/cassava |
| Uploaded | by AndreasAbel at 2025-09-02T12:50:09Z |
| Category | Text, Web, CSV |
| Home page | https://github.com/haskell-hvr/cassava |
| Bug tracker | https://github.com/haskell-hvr/cassava/issues |
| Source repo | head: git clone https://github.com/haskell-hvr/cassava.git |
| Distributions | Arch:0.5.4.1, Debian:0.5.2.0, Fedora:0.5.3.2, FreeBSD:0.4.3.1, LTSHaskell:0.5.4.1, NixOS:0.5.4.1, Stackage:0.5.4.1, openSUSE:0.5.4.1 |
| Reverse Dependencies | 100 direct, 3754 indirect [details] |
| Downloads | 78844 total (82 in the last 30 days) |
| Rating | 2.5 (votes: 13) [estimated by Bayesian average] |
| Your Rating |
|
| Status | Docs available [build log] Last success reported on 2025-09-02 [all 1 reports] |
Readme for cassava-0.5.4.1
[back to package description]cassava: A CSV parsing and encoding library
Please refer to the package description for an overview of cassava.
Usage example
Here's the two second crash course in using the library. Given a CSV file with this content:
John Doe,50000
Jane Doe,60000
here's how you'd process it record-by-record:
{-# LANGUAGE ScopedTypeVariables #-}
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V
main :: IO ()
main = do
csvData <- BL.readFile "salaries.csv"
case decode NoHeader csvData of
Left err -> putStrLn err
Right v -> V.forM_ v $ \ (name, salary :: Int) ->
putStrLn $ name ++ " earns " ++ show salary ++ " dollars"
If you want to parse a file that includes a header, like this one
name,salary
John Doe,50000
Jane Doe,60000
use decodeByName:
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V
data Person = Person
{ name :: !String
, salary :: !Int
}
instance FromNamedRecord Person where
parseNamedRecord r = Person <$> r .: "name" <*> r .: "salary"
main :: IO ()
main = do
csvData <- BL.readFile "salaries.csv"
case decodeByName csvData of
Left err -> putStrLn err
Right (_, v) -> V.forM_ v $ \ p ->
putStrLn $ name p ++ " earns " ++ show (salary p) ++ " dollars"
You can find more code examples in the examples/ folder as well as smaller usage examples in the Data.Csv module documentation.
Project Goals for cassava
There's no end to what people consider CSV data. Most programs don't
follow RFC4180 so one has to
make a judgment call which contributions to accept. Consequently, not
everything gets accepted, because then we'd end up with a (slow)
general purpose parsing library. There are plenty of those. The goal
is to roughly accept what the Python
csv module accepts.
The Python csv module (which is implemented in C) is also considered
the base-line for performance. Adding options (e.g. the above
mentioned parsing "flexibility") will have to be a trade off against
performance. There's been complaints about performance in the past,
therefore, if in doubt performance wins over features.
Last but not least, it's important to keep the dependency footprint light, as each additional dependency incurs costs and risks in terms of additional maintenance overhead and loss of flexibility. So adding a new package dependency should only be done if that dependency is known to be a reliable package and there's a clear benefit which outweights the cost.
Further reading
The primary API documentation for cassava is its Haddock documentation which can be found at https://hackage.haskell.org/package/cassava/docs/Data-Csv.html
Below are listed additional recommended third-party blogposts and tutorials