I have a CSV with fields in it which contain unit values which I have to parse out. As a simple example:
data EValue = Farads Double | MicroFarads Double | PicoFarads Double
Thus I need to parse something like the following:
parseEValue = farads <|> micro <|> pico
where farads = Farads <$> double <* string "F"
micro = MicroFarads <$> double <* string "µF"
pico = PicoFarads <$> double <* string "pF"
How do I include this in an instance definition for FromField
for Cassava
?
instance FromField EValue where
parseField = ???
You just need to run attoparsec on the Field
you get and then put the result in the Parser
monad, like this: parseField = either fail pure . parseOnly parseEValue
.
For completeness, here's everything put together:
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import Data.Attoparsec.ByteString.Char8
import Data.Csv
data EValue = Farads Double | MicroFarads Double | PicoFarads Double
parseEValue = farads <|> micro <|> pico
where farads = Farads <$> double <* string "F"
micro = MicroFarads <$> double <* string "µF"
pico = PicoFarads <$> double <* string "pF"
instance FromField EValue where
parseField = either fail pure . parseOnly parseEValue
On an unrelated note, string "µF"
is unlikely to do what you want (except during testing with string literals as input). You probably want something like import qualified Data.Text.Encoding as T
and string (T.encodeUtf8 "µF")
instead. See Surprising behavior of ByteString literals via IsString for details.