我试图从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。谢谢!
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发布于 2017-03-21 23:41:44
您要寻找的是一个适应JSON解码器的函数:
decodeJson :: forall a. Json -> Either String a使用F而不是Either返回。F是在Data.Foreign中定义的Except MultipleErrors a同义词。要做到这一点,我们需要:
String错误转换为MultipleErrorsEither到Except的转换MultipleErrors是在Data.Foreign中定义的另一个同义词,这次用于NonEmptyList ForeignError。ForeignError有一个构造函数,也称为ForeignError,它允许我们提供一些字符串消息。这就使得我们需要创建一个NonEmptyList,这非常容易:
remapError = pure <<< ForeignErrorNonEmptyList是Applicative,所以我们可以用pure创建一个单元素列表。
从Either到Except也很简单。同样,寻找追求中的定义我们可以看到:
newtype ExceptT m e a = ExceptT (m (Either e a))
type Except = ExceptT Identity所以ExceptT已经是一个花哨的Either了,它给了我们:
eitherToExcept = ExceptT <<< pure这里的pure是将Either e a提升到m (Either e a)中,后者用于Except m ~ Identity。
因此,现在我们可以使用这些内容,并创建一个通用的“解码用于Affjax响应的JSON”函数:
decodeJsonResponse :: forall a. DecodeJson a => Json -> F a
decodeJsonResponse =
ExceptT <<< pure <<< lmap (pure <<< ForeignError) <<< decodeJson这里发生的另一件事是,我们使用lmap在Either的左侧进行映射,以执行错误消息类型转换位。
现在我们可以使用Kleisli组合((<=<) )将这个decodeJsonResponse与将执行初始ResponseContent -> F Json的原始fromResponse链接在一起。
instance respondableAnswer :: Respondable Answer where
responseType = Tuple (Just applicationJSON) JSONResponse
fromResponse = decodeJsonResponse <=< fromResponse下面是使用Answer类型的完整示例:
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) <<< decodeJsonhttps://stackoverflow.com/questions/42927827
复制相似问题