将替换的嵌套模式替换为Monad的"do"

アレッ*_*ックス 5 haskell

我想简化这段代码

{-# 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)

我该如何解决这些错误?

iam*_*nat 1

因此 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