Transposition exchanges the row-and-column orientation of a rectangular collection. In a CSV parser, it turns parsed rows into columns; when writing a CSV, it turns stored columns back into rows. section 8.2.4 section 8.3
Rotating rows into columns
import Data.List (transpose) transpose [[1,2,3], [4,5,6]] -- [[1,4], [2,5], [3,6]] section 8.2.4
Use transposition at the boundaries of a CSV workflow:
- Parse each input line into fields, validate its field count, accumulate the rows, and transpose the result into columns. section 8.2.4
- Convert stored columns back into rows before mapping values to text, joining fields with commas, and writing the file. section 8.3
Listing 8.6 The function to parse lines of text into columns in a CSV table
parseColumns ::
Int ->
[(Int, T.Text)] ->
Either String [[DataField]]
parseColumns expectedLength lines =
let textColumns =
L.transpose #1
<$> L.foldl' parseRow (Right []) lines #2
in fmap (L.map (L.map textToDataField)) textColumns
where
parseRow ::
Either String [[T.Text]] ->
(Int, T.Text) ->
Either String [[T.Text]]
parseRow mRows (lNum, line) =
E.either #3
Left
( \rows ->
let fields = splitFields line #4
in if length fields /= expectedLength
then
Left $ #5
"Number of fields in line "
<> show lNum
<> " does not match"
<> " expected length of "
<> show expectedLength
<> "! Actual length is "
<> show (length fields)
<> "!"
else Right $ rows ++ [fields] #6
)
mRows
Inspect the complete CSV column-parsing function, including the fold, row validation, error propagation, and transpose step. section 8.2.4





