我想简化这段代码
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import Network.HTTP.Types
import Data.Text
getJSON :: String -> IO (Either String Value)
getJSON url = eitherDecode <$> simpleHttp url
--------------------------------------------------------------------
maybeJson <- getJSON "abc.com"
case maybeJson of
Right jsonValue -> case jsonValue of
(Object jsonObject) ->
case (HashMap.lookup "key123" jsonObject) of
(Just (String val)) -> Data.Text.IO.putStrLn val
_ -> error "Couldn't get the key"
_ -> error "Unexpected JSON"
Left errorMsg -> error $ "Error in parsing: " ++ errorMsg
Run Code Online (Sandbox Code Playgroud)
通过使用Monad的do语法
maybeJson <- getJSON "abc.com/123"
let toPrint = do
Right jsonValue <- maybeJson
Object jsonObject <- jsonValue
Just (String val) <- HashMap.lookup "key123" jsonObject
return val
case toPrint of
Just a -> Data.Text.IO.putStrLn a
_ -> error "Unexpected JSON"
Run Code Online (Sandbox Code Playgroud)
它给了我3个错误:
src/Main.hs:86:19:
Couldn't match expected type `Value'
with actual type `Either t0 (Either String Value)'
In the pattern: Right jsonValue
In a stmt of a 'do' block: Right jsonValue <- maybeJson
src/Main.hs:88:19:
Couldn't match expected type `Value' with actual type `Maybe Value'
In the pattern: Just (String val)
In a stmt of a 'do' block:
Just (String val) <- HashMap.lookup "key123" jsonObject
src/Main.hs:88:40:
Couldn't match type `Maybe' with `Either String'
Expected type: Either String Value
Actual type: Maybe Value
Even when I replace
Just (String val) <- HashMap.lookup "key123" jsonObject
Run Code Online (Sandbox Code Playgroud)
同
String val <- HashMap.lookup "key123" jsonObject
Run Code Online (Sandbox Code Playgroud)
我收到另一个关于Either的类似错误:
Couldn't match type `Maybe' with `Either String'
Expected type: Either String Value
Actual type: Maybe Value
In the return type of a call of `HashMap.lookup'
In a stmt of a 'do' block:
String val <- HashMap.lookup "key123" jsonObject
Run Code Online (Sandbox Code Playgroud)
我该如何解决这些错误?
因此 Monad 的 do 表达式中的每一行都必须返回该 Monadic 类型的值。Monad 在这里是一个类型类,而不是它本身的类型。因此,将所有内容都放在 do Monad 中并不是一个明智的声明。
您可以尝试将所有内容都包含在 Maybe monad 中的代码。假设您已获取 JSON 值:
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import Network.HTTP
import qualified Data.Map as M
import Control.Applicative
import qualified Data.HashMap.Strict as HM
--------------------------------------------------------------------
main = do
maybeJson <- return $ toJSON (M.fromList [("key123","value")] :: M.Map String String)
ioVal <- return $ do -- The Maybe monad do expression starts here
maybeJson <- Just maybeJson
jsonObject <- case maybeJson of
Object x -> Just x
_ -> Nothing
val <- HM.lookup "key123" jsonObject
return val
putStrLn $ show ioVal
Run Code Online (Sandbox Code Playgroud)
一旦我们开始使用 Maybe monad,每个表达式都必须返回一个Maybe Something值。monad 的工作方式Maybe是,任何 a 都会作为您可以使用的Just something纯代码出现,但如果您得到 a ,则将跳过其余代码,您将得到一个。somethingNothingNothing
这种跌倒的属性是 Maybe monad 所独有的。不同的单子有不同的行为。
您应该在这里阅读有关 Monad 和 IO monad 的更多信息:http://www.haskell.org/haskellwiki/Introduction_to_IO
您应该阅读更多有关 monad 以及它们真正帮助您做什么的内容: http://learnyouahaskell.com/a-fistful-of-monads (您应该完成前面的章节,然后再阅读本章。一旦完成,您就可以了)将对正在发生的事情有一个非常扎实的了解)。
我还认为你的 HTTP 请求搞砸了。以下是您可以使用的 POST 请求的示例。
import qualified Network.HTTP as H
main = do
postData <- return $ H.urlEncodeVars [("someVariable","someValue")]
request <- return $ H.postRequestWithBody "http://www.google.com/recaptcha/api/verify" "application/x-www-form-urlencoded" postData
putStrLn $ show request
-- Make the request
(Right response) <- H.simpleHTTP request
-- Print status code
putStrLn $ show $ H.rspCode response
-- Print response
putSrLn $ show $ H.rspBody response
Run Code Online (Sandbox Code Playgroud)
更新:使用以下内容来帮助您获取 JSON 值:
import qualified Data.ByteString.Lazy as LC
import qualified Data.ByteString.Char8 as C
import qualified Data.Aeson as DA
responseBody <- return $ H.rspBody response
responseJSON <- return (DA.decode (LC.fromChunks [C.pack responseBody]) :: Maybe DA.Value)
Run Code Online (Sandbox Code Playgroud)
您必须创建一个请求对象才能发出请求。帮手的人还蛮多的。我的意思是发布请求是最常见的情况: http://hackage.haskell.org/package/HTTP-4000.0.5/docs/Network-HTTP.html