Haskell 用“替换嵌套模式匹配”;“做”;单子

Haskell 用“替换嵌套模式匹配”;“做”;单子,haskell,Haskell,我想简化这段代码 {-# LANGUAGE OverloadedStrings #-} import Data.Aeson import Network.HTTP.Types import Data.Text getJSON :: String -> IO (Either String Value) getJSON url = eitherDecode <$> simpleHttp url -----------------------------------------

我想简化这段代码

{-# 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
{-#语言重载字符串}
导入数据.Aeson
导入Network.HTTP.Types
导入数据.Text
getJSON::String->IO(任意字符串值)
getJSON url=eitherDecode simpleHttp url
--------------------------------------------------------------------
maybeJson案例jsonValue的
(对象jsonObject)->
的大小写(HashMap.lookup“key123”jsonObject)
(Just(String val))->Data.Text.IO.putStrLn val
_->错误“无法获取密钥”
_->错误“意外的JSON”
Left errorMsg->error$”解析错误:“++errorMsg”
通过对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"

maybeJson您不能简单地将其简化为一个单独的do表示法块,因为每个
case
都在不同的类型上匹配。第一个是解包
或者
,第二个是a
,第三个是a
可能
。Do表示法的工作原理是通过单个类型将所有内容线程化,因此它在这里不直接适用

您可以将所有案例转换为使用同一个monad,然后将其全部写入do块。例如,您可以使用帮助器函数进行第二个和第三个模式匹配,并生成相应的
。然而,这和你现在拥有的并没有多大区别

事实上,如果我采用这种方法,我只会满足于将两个内部匹配提取到它们自己的
where
变量中,并保持不变。试图把整个事情放在一个单子里只会混淆问题;这不是正确的抽象概念

相反,您可以获得一种不同的抽象。特别是,考虑使用<代码>晶状体库,它有棱镜用于嵌套模式匹配。它甚至自然地支持埃森!您所需的函数如下所示:

decode :: String -> Maybe Value
decode json = json ^? key "key123"
您还可以将其与更具体的棱柱相结合,例如,如果您需要字符串值:

decode :: String -> Maybe String
decode json = json ^? key "key123" . _String

这负责解析json,确保它是一个对象,并获取指定键上的任何内容。唯一的问题是,它没有给你一个有用的错误消息,说明它为什么失败;不幸的是,我对lens不够好,无法理解如何解决这个问题(如果可能的话)。

因为您是IO单子,所以所有的
都必须返回该单子类型的值。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
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)
更新: 使用以下命令可帮助您获取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
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)
import qualified Data.ByteString.Lazy作为LC
将限定的Data.ByteString.Char8作为C导入
导入合格数据。Aeson作为DA

我不懂密码。什么是
maybeJson
maybeJson::字符串值
@Zeta:ack,你是对的。但是,如果您修复它并将my
maybeJSON
替换为
getJSON
,那么问题仍然存在。不过,我不确定是否值得修复这个答案,因为我不喜欢那样的
错误
-ing,do块可能都在IO monad中,通过在
中使用失败的模式匹配,您可以获得与原始程序类似的行为,我现在不想使用lens,因为它是第三方库,这不是Haskell的一部分,谢谢。为什么你认为http请求被搞砸了?首先,它是一个get请求。而且你的版本更复杂,不是吗?我认为这不会编译。您必须将字符串响应转换为
Lazy ByteString
ByteString
才能使用
Aeson
。更新了答案。
do 
    Right jsonValue <- maybeJson
    let Object jsonObject = jsonValue
{-# 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
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
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)