2

I'm using Aeson to parse json quote data from Yahoo's API. A quote might look like this:

{
  "date": "2010-03-10",
  "Date": "2010-03-10",
  "Open": "0.37",
  "High": "0.37",
  "Low": "0.34",
  "Close": "0.35",
  "Volume": "443000",
  "Adj_Close": "0.35"
}

(that's using this YQL query)

As you can see, the numbers are quoted. I can write a fromJSON implementation like this:

instance FromJSON Quote where
  parseJSON (Object o) =
    Quote <$> o .: "Date"
          <*> o .: "Open"
          <*> o .: "High"
          <*> o .: "Low"
          <*> o .: "Close"
          <*> o .: "Volume"
  parseJSON _ = mzero

which is the same as what would be derived. Unfortunately this only works if I want Open, High, Low, etc, to be a Text type. The parse fails if I try and have any of those fields as Double, say.

I can write this:

<*> (fmap read $ o .: "Open")

to get it as anything I like, but this uses read, which is a partial function. How would I get the above functionality without using a partial function?

4

1 回答 1

1

首先,找到一个安全读取功能。我不得不胡说八道

其次,您必须使用不仅仅是应用程序来获得选择。在下面,我使用readMay了安全读取并制作了一个辅助函数来在应用 Read 实例时提取字段。

{-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction #-}
import Safe
import Data.Aeson
import Data.Aeson.Types (Parser)
import Data.Text as T
import Data.Word
import Control.Applicative
import Control.Monad

data Quote = Quote Text Double Double Double Double Word64
instance FromJSON Quote where
  parseJSON (Object o) = do
    let readField :: (Read a) => T.Text -> Parser a
        readField f = do
            v <- o .: f
            case readMay (T.unpack v) of
                Nothing -> fail $ "Bad Field: " ++ T.unpack f
                Just r  -> return r
    Quote <$> o .: "Date"
          <*> readField "Open"
          <*> readField "Close"
          <*> readField "Low"
          <*> readField "High"
          <*> readField "Volume"
  parseJSON _ = mzero
于 2013-10-30T03:47:20.983 回答