polytropos-cassava
Copyright(c) 2026 The Polytropos Authors
LicenseEUPL-1.2 OR Apache-2.0
Maintainernadia.yvette.chambers@ik.me
Stabilityexperimental
Portabilitynon-portable (GHC extensions)
Safe HaskellNone
LanguageGHC2021

Polytropos.Cassava

Description

Connects polytropos open records to the standard Haskell CSV library cassava without intermediate nominal conversions: ToNamedRecord serializes field names and values straight from the flat Rep payload, and FromNamedRecord looks up each field label in the CSV header map in \(O(1)\).

Architectural Overview & Rationale

Heterogeneous Row Support

Unlike satellites that require homogeneous rows, polytropos-cassava is genuinely heterogeneous: the AllToField and AllFromField row constraint walks require the CSV field classes (ToField / FromField) at each field's own type, so a row mixing String, Int, and Double columns encodes and decodes directly.

Decoding is strict about field presence (a missing header column fails), but ignores extra columns in the CSV input, matching cassava's own generic behaviour.

When to Use This Module

  • When reading or writing CSV files, spreadsheets, or tabular datasets using open records.

Worked Example

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fplugin=Polytropos.Plugin #-}

import qualified Data.Csv as Csv
import Polytropos
import Polytropos.Cassava

type UserRow = Record '["username" ':= String, "score" ':= Int]

row :: UserRow
row = REC { username = "Alice", score = 95 }

-- Encodes to CSV named record:
namedRec = Csv.toNamedRecord row
Synopsis

Row Constraint Walks

class AllToField (r :: Row) where Source #

Evidence that every field of the row r has a ToField instance at that field's own type — the heterogeneous analogue of a constraint fold. The walk applies toField to each erased payload slot exactly where the row structure guarantees the slot's type.

Methods

encFields :: Proxy r -> [Identity (Any :: Type)] -> [ByteString] Source #

Instances

Instances details
AllToField ('[] :: [Pair Symbol Type]) Source # 
Instance details

Defined in Polytropos.Cassava

Methods

encFields :: Proxy ('[] :: [Pair Symbol Type]) -> [Identity (Any :: Type)] -> [ByteString] Source #

(KnownSymbol n, ToField a, AllToField r) => AllToField ((n ':= a) ': r) Source # 
Instance details

Defined in Polytropos.Cassava

Methods

encFields :: Proxy ((n ':= a) ': r) -> [Identity (Any :: Type)] -> [ByteString] Source #

class AllFromField (r :: Row) where Source #

Heterogeneous decode walk: every field of the row r has a FromField instance at its own type, and decFields looks each column up by name in O(1).

Methods

decFields :: Proxy r -> NamedRecord -> Parser [Identity (Any :: Type)] Source #

Instances

Instances details
AllFromField ('[] :: [Pair Symbol Type]) Source # 
Instance details

Defined in Polytropos.Cassava

Methods

decFields :: Proxy ('[] :: [Pair Symbol Type]) -> NamedRecord -> Parser [Identity (Any :: Type)] Source #

(KnownSymbol n, FromField a, AllFromField r) => AllFromField ((n ':= a) ': r) Source # 
Instance details

Defined in Polytropos.Cassava

Methods

decFields :: Proxy ((n ':= a) ': r) -> NamedRecord -> Parser [Identity (Any :: Type)] Source #

Row Introspection

class FieldNames (r :: Row) where Source #

The field names of a row, in row order, reified from the type level.

Methods

fieldNames :: Proxy r -> [String] Source #

Instances

Instances details
FieldNames ('[] :: [Pair Symbol Type]) Source # 
Instance details

Defined in Polytropos.Cassava

Methods

fieldNames :: Proxy ('[] :: [Pair Symbol Type]) -> [String] Source #

(KnownSymbol n, FieldNames r) => FieldNames ((n ':= a) ': r) Source # 
Instance details

Defined in Polytropos.Cassava

Methods

fieldNames :: Proxy ((n ':= a) ': r) -> [String] Source #

Orphan instances

AllFromField r => FromNamedRecord (Record r) Source # 
Instance details

(FieldNames r, AllToField r) => ToNamedRecord (Record r) Source # 
Instance details