如何在不声明单个类型的情况下解析JSON与Aeson

时间:2016-01-29 05:31:28

标签: haskell aeson

(Haskell新手警报)

这是我所挣扎的代码片段。基本上,我从websocket中获取JSON,我想使用Aeson解析它而不为每个响应定义单独的数据类型。

import Data.Aeson
import qualified Network.WebSockets  as WS

aria2WebsocketReceiver :: WS.Connection -> IO ()
aria2WebsocketReceiver conn = do
  msg <- WS.receiveData conn
  let res = decode msg
  let v = flip parseMaybe res $ \o -> do
                                      r <- o .: "result"
                                      version <- r .: "version"
                                      enabledFeatures <- r .: "enabledFeatures"
                                      id_ <- r .: "id"
                                      return $ "version=" ++ version
  putStrLn (show v)
  aria2WebsocketReceiver conn

以下是我遇到的编译错误:

Nightwatch/Telegram.hs:244:13:
    No instance for (FromJSON a0) arising from a use of ‘decode’
    The type variable ‘a0’ is ambiguous
    Relevant bindings include
      res :: Maybe a0 (bound at Nightwatch/Telegram.hs:244:7)
    Note: there are several potential instances:
      instance FromJSON Chat -- Defined at Nightwatch/Telegram.hs:90:10
      instance FromJSON Message
        -- Defined at Nightwatch/Telegram.hs:106:10
      instance FromJSON TelegramResponse
        -- Defined at Nightwatch/Telegram.hs:122:10
      ...plus two others
    In the expression: decode msg
    In an equation for ‘res’: res = decode msg
    In the expression:
      do { msg <- WS.receiveData conn;
           let res = decode msg;
           let v = flip parseMaybe res $ ...;
           putStrLn (show v);
           .... }

Nightwatch/Telegram.hs:246:44:
    Couldn't match type ‘Maybe a0’
                   with ‘unordered-containers-0.2.5.1:Data.HashMap.Base.HashMap
                           Text Value’
    Expected type: Object
      Actual type: Maybe a0
    Relevant bindings include
      o :: Maybe a0 (bound at Nightwatch/Telegram.hs:245:34)
      res :: Maybe a0 (bound at Nightwatch/Telegram.hs:244:7)
    In the first argument of ‘(.:)’, namely ‘o’
    In a stmt of a 'do' block: r <- o .: "result"

我基本上试图复制&#34;使用AST&#34;在https://hackage.haskell.org/package/aeson-0.10.0.0/docs/Data-Aeson.html

给出的示例

1 个答案:

答案 0 :(得分:6)

感谢Cale在#haskell这里的工作代码:

aria2WebsocketReceiver :: WS.Connection -> IO ()
aria2WebsocketReceiver conn = do
  msg <- WS.receiveData conn
  let v = do res <- decode msg
             flip parseMaybe res $ \o -> do
                                         r <- o .: "result"
                                         version <- r .: "version"
                                         return $ "version=" ++ (version :: String)
  putStrLn (show v)
  aria2WebsocketReceiver conn

早期代码中存在三个问题:

  1. decode msg的类型是Maybe,需要位于单独的do区块内。
  2. 由于{-# LANGUAGE OverloadedStrings #-},编译器无法推断version的类型,因此(version :: String)提示。
  3. 同样,enabledFeaturesid_被分配但未在任何地方使用,这导致了类型推断中的更多问题。