2017-03-21 5 views
2

私はHaskellサーバーからJSONデータを取得しようとしていますが、一般的なAffjaxだけでなくResponderableインスタンスにも問題があります。私はData.Argonaut.Generic.Aeson(GA)でEncodeJson + DecodeJsonを定義しましたが、Responderableインスタンスでそれをどのように適合させるかを理解できず、fromResponse関数です。Purescript再利用Argonaut JSONデコードfor Affjax Respondable

エラー "私はタイプ外国人とタイプJsonを一致させることができませんでしたが、"手で他のものを作成することなく私のdecodeJsonインスタンスを再利用することは可能ですか?たぶん、IsForeignインスタンスを作成して、その中にGA.decodeJsonを使用しますか?私はそれをやり遂げる方法については分かりません。私はそれが手でhttps://github.com/purescript/purescript-foreign/blob/master/examples/Complex.pursでどのように行われているのか見てきましたが、私はHaskellのJSON出力と一致する必要がある複雑な型を持っています、そして、手動で行うには巨大な苦痛になるでしょう。

purescript 10.7、Affjax 3.02、argonaut 2.0.0、argonaut-generic-codecs 5.1.0を使用しています。ありがとう!

decodeJson :: forall a. Json -> Either String a 

EitherではなくFを使用して戻すには:

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 

答えて

7

は何あなたが探しているのはJSONデコーダを適応させる機能です。 Fは、Except MultipleErrors aの場合、Data.Foreignで定義される同義語です。 EitherからExcept

MultipleErrorsに変換MultipleErrors

  • に私達のStringエラーを翻訳

    1. Data.Foreignで定義された別の同義語、NonEmptyList ForeignErrorのためのこの時間です:我々は必要なことをすることができません。 Looking at ForeignErrorForeignErrorとも呼ばれるコンストラクタがあり、文字列メッセージを提供します。

      remapError = pure <<< ForeignError 
      

      NonEmptyListApplicativeあるので、我々はpureと1要素のリストを作成することができます:それは非常に簡単ですNonEmptyListを作成する必要、と私たちを残します。

      EitherからExceptへ行くことも簡単です。再びlooking at the definitions in Pursuit私たちが見ることができます:

      newtype ExceptT m e a = ExceptT (m (Either e a)) 
      type Except = ExceptT Identity 
      

      のでExceptTを私たちに与えて、すでに単なる空想Eitherです:

      eitherToExcept = ExceptT <<< pure 
      

      ここpureExceptm ~ Identityため、m (Either e a)Either e aを持ち上げることです。

      だから今、私たちはこのようなものを取る、と機能一般的な「Affjax応答のデコードJSON」を作ることができます。

      decodeJsonResponse :: forall a. DecodeJson a => Json -> F a 
      decodeJsonResponse = 
          ExceptT <<< pure <<< lmap (pure <<< ForeignError) <<< decodeJson 
      

      ここで起こった唯一の他の事は、我々は左部分の上にマッピングするためにlmapを使用していますEitherのエラーメッセージタイプ変換ビットを実行する。

      私たちは今何だろう、元fromResponseと、このdecodeJsonResponse一緒にチェーンにKleisli組成物((<=<))を使用することができResponseContent -> F Json初期:

      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 
      

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

      ここにあなたのAnswerタイプを使用して完全な例です

  • +0

    それは恐ろしいです。ここで何が起こっているのかを理解するのにもう時間がかかりますが、うまくいきます。ありがとう! – sportanova

    +0

    これをライブラリとして持っているとよいでしょう。ありがとう! – gueux