Haskell Aeson:如何从IO monad中的解析器获取值

4

我正在尝试在IO中进行JSON解析:

{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import Data.Aeson
import Data.Maybe (fromJust)

main :: IO ()
main = do
  response <- getResponseBody <$> httpJSON "http://localhost:9200" :: IO Object
  name <- fromJust <$> response .: "name" :: Parser String
  print "hi"

I get the error:

/home/nut/dev/haskell/elastic/app/Main.hs:39:11: error:
     Couldn't match type ‘Parser’ with ‘IO’
      Expected type: IO String
        Actual type: Parser String
     In a stmt of a 'do' block:

那么,我该如何从json结果中获取`name`?

2
看起来你正在尝试将 fromJust <$> response .: "name" 的结果绑定到 IO 中,但它只是一个 Parser 值。我对 Aeson 不是很熟悉,但我认为你需要使用 Data.Aeson.Types.parseparseMaybe 来运行解析器(纯粹地)。 - Jon Purdy
1个回答

6
Aeson有一系列将Parser a转换为a的函数:
parse       :: (a -> Parser b) -> a -> Result b
parseEither :: (a -> Parser b) -> a -> Either String b
parseMaybe  :: (a -> Parser b) -> a -> Maybe b

所以,如果你有例如。
(.: "name") :: Object -> Parser String

那么你就需要:
parseMaybe (.: "name") :: Object -> Maybe String

因此您可以这样做

{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import Data.Aeson
import Data.Maybe (fromJust)
import Data.Aeson.Types -- new import for parseMaybe

main :: IO ()
main = do
    response <- getResponseBody <$> httpJSON "http://localhost:9200"
    let name = fromJust $ parseMaybe (.: "name") response :: String
    print "hi"

现在我有点困惑。难道不应该是 (.: "name") :: Value -> Parser String 吗?Object 的类型是 Value 吗?对于 Aeson 库感到困惑,很抱歉... - LudvigH
是的,没错。整个表达式 fromJust $ parseMaybe (.: "name") response 的类型被我们注释为 String: (.: "name") :: Value -> Parser String,而 response :: Value,因此我们可以使用 parseMaybe :: (a -> Parser b) -> a -> Maybe b,其中 a ~ Valueb ~ String - Cactus
1
当然,如果我们只是在任何情况下都使用 name(比如将最后一行从 print "hi" 更改为 putStrLn $ unwords ["Hi,", name]),那么它就会指定其类型,那么我们就不需要在 let name = ... 行中加上类型注释。 - Cactus
我明白了。我对多态性还不太熟悉,所以这个解释很有帮助。:) 非常感谢! - LudvigH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接