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

Sau*_*nda 2 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
Run Code Online (Sandbox Code Playgroud)

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

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"
Run Code Online (Sandbox Code Playgroud)

我基本上试图复制https://hackage.haskell.org/package/aeson-0.10.0.0/docs/Data-Aeson.html上给出的"使用AST"示例.

Sau*_*nda 6

感谢Cale at #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
Run Code Online (Sandbox Code Playgroud)

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

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

  • 关于3,这是Haskell(GHC)的典型问题,特别是对于提供DSL的库 - 它们依赖于*类型推理*来工作,并且类型推断仅在您实际使用某个值的类型时才有效!这在实践中显然很好,但在测试和试验时,您经常会遇到这种情况.一般来说,"模糊类型"错误对应于此类(未使用的多态值) - 如果您看到此错误,请查找此类事物. (2认同)