Parsing JSON string into record in Haskell

前端 未结 5 2229
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-31 10:42

I\'m struggling to understand this (I\'m still a bit new to Haskell) but I\'m finding the documentation for the Text.JSON package to be a little confusing. Basicall

5条回答
  •  天命终不由人
    2021-01-31 11:26

    I'd recommend that you use the new aeson package instead of the json package, as the former performs much better. Here's how you'd convert a JSON object to a Haskell record, using aeson:

    {-# LANGUAGE OverloadedStrings #-}
    module Example where
    
    import Control.Applicative
    import Control.Monad
    import Data.Aeson
    
    data Tweet = Tweet {
        from_user :: String,
        to_user_id :: String,
        profile_image_url :: String,
        created_at :: String,
        id_str :: String,
        source :: String,
        to_user_id_str :: String,
        from_user_id_str :: String,
        from_user_id :: String,
        text :: String,
        metadata :: String
        }
    
    instance FromJSON Tweet where
        parseJSON (Object v) =
            Tweet <$> v .: "from_user"
                  <*> v .: "to_user_id"
                  <*> v .: "profile_image_url"
                  <*> v .: "created_at"
                  <*> v .: "id_str"
                  <*> v .: "source"
                  <*> v .: "to_user_id_str"
                  <*> v .: "from_user_id_str"
                  <*> v .: "from_user_id"
                  <*> v .: "text"
                  <*> v .: "metadata"
        -- A non-Object value is of the wrong type, so use mzero to fail.
        parseJSON _          = mzero
    

    Then use Data.Aeson.json to get a attoparsec parser that converts a ByteString into a Value. The call fromJSON on the Value to attempt to parse it into your record. Note that there are two different parsers involved in these two steps, a Data.Attoparsec.Parser parser for converting the ByteString into a generic JSON Value and then a Data.Aeson.Types.Parser parser for converting the JSON value into a record. Note that both steps can fail:

    • The first parser can fail if the ByteString isn't a valid JSON value.
    • The second parser can fail if the (valid) JSON value doesn't contain one of the fields you mentioned in your fromJSON implementation.

    The aeson package prefers the new Unicode type Text (defined in the text package) to the more old school String type. The Text type has a much more memory efficient representation than String and generally performs better. I'd recommend that you change the Tweet type to use Text instead of String.

    If you ever need to convert between String and Text, use the pack and unpack functions defined in Data.Text. Note that such conversions require O(n) time, so avoid them as much as possible (i.e. always use Text).

提交回复
热议问题