0

So I was writing a small toybox of utility functions for CSV files and throughout testing the functions I'd been binding the file by hand with

table' <- parseCSVFromFile filepath

but (from Text.CSV)

parseCSVFromFile :: FilePath -> IO (Either parsec-3.1.9:Text.Parsec.Error.ParseError CSV)

and so I had to write a quick line to strip off this either error csv crap

stripBare csv = head $ rights $ flip (:) [] csv

and redefine it as table = stripBare table'. After this, list functions work on the csv files contents and life goes on

(Digression: Surprisingly there isn't a direct Either a b -> b function in Data.Either. So I used Data.Either.rights :: [Either a b] -> [b])

I wanted to do the work of undressing the csv type and binding it to a handle in one shot. Something like

table = stripBare $ table' <- parseCSVFromFile filepath

but this gives a parse error on (<-) saying I may be missing a do... then

table = stripBare $ do table' <- parseCSVFromFile filepath

yells at me saying that the last statement in a do block must be an expression.

What am I doing wrong?

As a separate curiosity, I saw here that

do notation in Haskell desugars in a pretty simple way.

do
  x <- foo
  e1 
  e2
  ...

turns into

 foo >>= \x ->
 do
   e1
   e2

I find this attractive and tried the following line which gave me a type error

*Toy> :type (parseCSVFromFile "~/.csv") >>= \x -> x

<interactive>:1:52: error:
    * Couldn't match type `Either
                             parsec-3.1.9:Text.Parsec.Error.ParseError'
                     with `IO'
      Expected type: IO CSV
        Actual type: Either parsec-3.1.9:Text.Parsec.Error.ParseError CSV
    * In the expression: x
      In the second argument of `(>>=)', namely `\ x -> x'
      In the expression:
        (parseCSVFromFile "~/.csv") >>= \ x -> x
Community
  • 1
  • 1
Tshimanga
  • 845
  • 6
  • 16

1 Answers1

0

Code such as

head $ rights $ flip (:) [] csv

is dangerous. You are exploiting the partiality of head to hide the fact that csv might be a Left something. We can rewrite it as

= head $ rights $ (:) csv []
= head $ rights [csv]
= case csv of
     Left _  -> error "Left found!"
     Right x -> x

Usually it's better to handle the Left case directly in the do IO block. Something like: (pseudo code follows)

foo :: String -> IO ()
foo filepath = do
   table' <- parseCSVFromFile filepath
   case table' of
      Left err -> do
         putStrLn "Error in parsing CSV"
         print err
         moreErrorHandlingHere
      Right table -> do
         putStrLn "CSV loaded!"
         use table
chi
  • 111,837
  • 3
  • 133
  • 218