首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Affjax中的Argonaut JSON解码

Affjax中的Argonaut JSON解码
EN

Stack Overflow用户
提问于 2017-03-21 12:57:01
回答 1查看 835关注 0票数 2

我试图从Haskell服务器上获取一些JSON数据,但是Respondeable实例以及普通的Affjax实例都有问题。我已经用EncodeJson + DecodeJson定义了Data.Argonaut.Generic.Aeson (GA),但是我不知道如何将它与Respondeable实例和它的fromResponse函数相匹配。

它给出了错误“无法匹配类型为Json的外部类型”,但是是否可以重用我的decodeJson实例而不必手工创建任何其他东西?也许通过创建一个IsForeign实例,但是在其中使用GA.decodeJson呢?我只是不知道该怎么做。我已经看到了手工在https://github.com/purescript/purescript-foreign/blob/master/examples/Complex.purs中是如何实现的,但是我有一些复杂的类型需要与我的Haskell输出相匹配,手动完成它将是一个巨大的痛苦。

我使用的是purescript 10.7,Affjax 3.02,argonaut 2.0.0和argonaut-泛型编解码器5.1.0。谢谢!

代码语言:javascript
复制
testAffjax :: forall eff. Aff (ajax :: AJAX | eff) (Answer)
testAffjax = launchAff do
  res <- affjax $ defaultRequest { url = "/", method = Left GET }
  pure res.response


data Answer = Answer {
  _answer :: String
, _isCorrect :: Boolean
, _hint :: String
}

{- PROBLEM -}
instance respondableAnswer :: Respondable Answer where
  responseType = Tuple Nothing JSONResponse
  fromResponse = GA.decodeJson {- Error here -}

derive instance genericAnswer :: Generic Answer
instance showAnswer :: Show Answer where
  show = gShow
instance encodeAnswer :: EncodeJson Answer where
  encodeJson = GA.encodeJson
instance decodeAnswer :: DecodeJson Answer where
  decodeJson = GA.decodeJson
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-21 23:41:44

您要寻找的是一个适应JSON解码器的函数:

代码语言:javascript
复制
decodeJson :: forall a. Json -> Either String a

使用F而不是Either返回。F是在Data.Foreign中定义的Except MultipleErrors a同义词。要做到这一点,我们需要:

  1. String错误转换为MultipleErrors
  2. EitherExcept的转换

MultipleErrors是在Data.Foreign中定义的另一个同义词,这次用于NonEmptyList ForeignErrorForeignError有一个构造函数,也称为ForeignError,它允许我们提供一些字符串消息。这就使得我们需要创建一个NonEmptyList,这非常容易:

代码语言:javascript
复制
remapError = pure <<< ForeignError

NonEmptyListApplicative,所以我们可以用pure创建一个单元素列表。

EitherExcept也很简单。同样,寻找追求中的定义我们可以看到:

代码语言:javascript
复制
newtype ExceptT m e a = ExceptT (m (Either e a))
type Except = ExceptT Identity

所以ExceptT已经是一个花哨的Either了,它给了我们:

代码语言:javascript
复制
eitherToExcept = ExceptT <<< pure

这里的pure是将Either e a提升到m (Either e a)中,后者用于Except m ~ Identity

因此,现在我们可以使用这些内容,并创建一个通用的“解码用于Affjax响应的JSON”函数:

代码语言:javascript
复制
decodeJsonResponse :: forall a. DecodeJson a => Json -> F a
decodeJsonResponse =
  ExceptT <<< pure <<< lmap (pure <<< ForeignError) <<< decodeJson

这里发生的另一件事是,我们使用lmapEither的左侧进行映射,以执行错误消息类型转换位。

现在我们可以使用Kleisli组合((<=<) )将这个decodeJsonResponse与将执行初始ResponseContent -> F Json的原始fromResponse链接在一起。

代码语言:javascript
复制
instance respondableAnswer :: Respondable Answer where
  responseType = Tuple (Just applicationJSON) JSONResponse
  fromResponse = decodeJsonResponse <=< fromResponse

下面是使用Answer类型的完整示例:

代码语言:javascript
复制
module Main where

import Prelude

import Control.Monad.Aff (Aff)
import Control.Monad.Except (ExceptT(..))

import Data.Argonaut (class DecodeJson, class EncodeJson, Json, decodeJson)
import Data.Argonaut.Generic.Argonaut as GA
import Data.Bifunctor (lmap)
import Data.Foreign (F, ForeignError(..))
import Data.Generic (class Generic, gShow)
import Data.Maybe (Maybe(..))
import Data.MediaType.Common as MediaType
import Data.Tuple (Tuple(..))

import Network.HTTP.Affjax as AX
import Network.HTTP.Affjax.Response as AXR

testAffjax :: forall eff. Aff (ajax :: AX.AJAX | eff) Answer
testAffjax = _.response <$> AX.get "/"

newtype Answer = Answer
  { _answer :: String
  , _isCorrect :: Boolean
  , _hint :: String
  }

derive instance genericAnswer :: Generic Answer

instance showAnswer :: Show Answer where
  show = gShow

instance encodeAnswer :: EncodeJson Answer where
  encodeJson = GA.encodeJson

instance decodeAnswer :: DecodeJson Answer where
  decodeJson = GA.decodeJson

instance respondableAnswer :: AXR.Respondable Answer where
  responseType = Tuple (Just MediaType.applicationJSON) AXR.JSONResponse
  fromResponse = decodeJsonResponse <=< AXR.fromResponse

decodeJsonResponse :: forall a. DecodeJson a => Json -> F a
decodeJsonResponse =
  ExceptT <<< pure <<< lmap (pure <<< ForeignError) <<< decodeJson
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42927827

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档