2016-12-28 9 views
0

GHCJSiバージョン0.2.0-7.10.3:http://www.github.com/ghcjs/ghcjs/https://github.com/reflex-frp/reflex-domからreflex-domライブラリバージョン0-4を使用しています。私はHackageからreflex-dom-0.3を使用していません。ハスケル:どのように "型変数のあいまいな"コンパイラエラーを修正するには?

次Haskellのプログラムは反射-DOM-0.4でコンパイルされません。

{-# LANGUAGE RecursiveDo, ScopedTypeVariables, DeriveGeneric, OverloadedStrings #-} 
import Reflex 
import Reflex.Dom 
import Data.Aeson 
import GHC.Generics 
import qualified Data.Text as T 
data Apod = Apod { copyright :: T.Text 
       , date :: T.Text 
       , explanation :: T.Text 
       , hdurl :: T.Text 
       , media_type :: T.Text 
       , service_version :: T.Text 
       , title :: T.Text 
       , url :: T.Text 
       } deriving (Generic, Show) 
instance FromJSON Apod 
main :: IO() 
main = do 
    mainWidget $ el "div" $ do 
    buttonEvent <- button "GET" 
    let url = "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY" 
    let defaultReq = xhrRequest "GET" url def 
    asyncEvent <- performRequestAsync (tag (constant defaultReq) buttonEvent) 
    let rspApod = fmapMaybe (\r -> decodeXhrResponse r) asyncEvent 
    return() 

私は反射-DOMライブラリ関数decodeXhrResponse(ともdecodeText)をインラインエラーに

Xhr00.hs:24:36: 
    No instance for (aeson-0.9.0.1:Data.Aeson.Types.Class.FromJSON b0) 
     arising from a use of ‘decodeXhrResponse’ 
    The type variable ‘b0’ is ambiguous 
    Relevant bindings include 
     rspApod :: Event Spider b0 (bound at Xhr00.hs:24:9) 
    Note: there is a potential instance available: 
     instance (aeson-0.9.0.1:Data.Aeson.Types.Class.FromJSON a, 
       aeson-0.9.0.1:Data.Aeson.Types.Class.FromJSON b) => 
       aeson-0.9.0.1:Data.Aeson.Types.Class.FromJSON 
       (Data.These.These a b) 
     -- Defined in ‘Data.These’ 
     In the expression: decodeXhrResponse r 
    In the first argument of ‘fmapMaybe’, namely 
     ‘(\ r -> decodeXhrResponse r)’ 
    In the expression: 
     fmapMaybe (\ r -> decodeXhrResponse r) asyncEvent 
Failed, modules loaded: none. 

を取得。私は、型名FromJSON a => XhrResponse -> Maybe aを型変数XhrResponse -> Maybe Apodのない署名に変更します。その後、プログラムは正常にコンパイルされます。

{-# LANGUAGE RecursiveDo, ScopedTypeVariables, DeriveGeneric, OverloadedStrings #-} 
import Reflex 
import Reflex.Dom hiding (decodeXhrResponse, decodeText) 
-- import Reflex.Dom 
import Data.Aeson 
import GHC.Generics 
import qualified Data.Text as T 
import Control.Monad 
import qualified Data.ByteString.Lazy as BL 
import Data.Text.Encoding 
data Apod = Apod { copyright :: T.Text 
       , date :: T.Text 
       , explanation :: T.Text 
       , hdurl :: T.Text 
       , media_type :: T.Text 
       , service_version :: T.Text 
       , title :: T.Text 
       , url :: T.Text 
       } deriving (Generic, Show) 
instance FromJSON Apod 
main :: IO() 
main = do 
    mainWidget $ el "div" $ do 
    buttonEvent <- button "GET" 
    let nasa = "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY" 
    let defaultReq = xhrRequest "GET" nasa def 
    asyncEvent <- performRequestAsync (tag (constant defaultReq) buttonEvent) 
    let rspApod :: Event Spider Apod = fmapMaybe (\r -> decodeXhrResponse r) asyncEvent 
    return() 
-- Inlined and changed library function: 
-- decodeXhrResponse :: FromJSON a => XhrResponse -> Maybe a 
decodeXhrResponse :: XhrResponse -> Maybe Apod 
decodeXhrResponse = join . fmap decodeText . _xhrResponse_responseText 
-- Inlined and changed library function: 
-- decodeText :: FromJSON a => T.Text -> Maybe a 
decodeText :: T.Text -> Maybe Apod 
decodeText = decode . BL.fromStrict . encodeUtf8 

私はrspApod :: Event t ApodまたはrspApod :: Event Spider ApodようrspApod用スコープ型変数を追加しようとしましたが、それは助けにはなりませんでした。

質問:

はどうすれば正常にコンパイルする最初のプログラムを変更する必要がありますか?

なぜ、コンパイラはApodデータ型のFromJSONインスタンスを見つけて使用しないのですか?いいえ、ライブラリの機能を変更することは非常に悪いハックです。

+0

'(\ r - > decodeXhrResponse r)'〜> 'decodeXhrResponse' –

+0

元のプログラムはあいまいです。型シグネチャ 'decodeXhrResponse r :: Maybe Apod'を追加するだけですか? –

+0

@Reid:ありがとうございますが、 'let rspApod = fmapMaybe(\ r - > decodeXhrResponse r :: Maybe Apod)asyncEvent'に変更しても問題は解決しません。同じ' No instance for'エラーが返されます。残念ながら... – Jogger

答えて

3

だから、関数のオリジナルの署名は、コンパイラを使用するので、

decodeXhrResponse :: FromJSON a => XhrResponse -> Maybe a

が与えられたaためFromJSONインスタンスを見つける必要があります。あなたのケースではaApodなので、コンパイラはApodFromJSONインスタンスを細かく設定する必要があります。あなたのコードでは、あなたの意図であることをコンパイラが知る方法はありません。これは、構文解析の際に共通の問題です。ここで、コンパイラは目標タイプが何を想定しているかを伝える必要があります。

ここでは、周囲のコード(asyncEventなど)によって目標タイプを判断できるはずだと主張することはできますが、何らかの理由でそうではありません。周囲のコードがまったく同じであるかもしれません。次のシナリオを検討し

main = print $ read x

どのようにコンパイラがxを読み取るためのターゲット・タイプを知ることができますか?

read :: Read a => String -> aこれは明らかにターゲットを通知しません。

print :: Show a => a -> IO()これは、aShowインスタンスである必要があると主張しています。

aはあまりにも一般的なため、解析することはできません。具体的なタイプが必要です。

したがって、関数をインライン化し、タイプシグネチャにApodを含めるように変更したときに、コンパイラに何を知る必要があるかを知る必要があります。FromJSONインスタンスを参照してください。ここで

は、私がこれを解決しただろうかです:

main :: IO() 
main = do 
    mainWidget $ el "div" $ do 
    buttonEvent <- button "GET" 
    let url = "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY" 
    let defaultReq = xhrRequest "GET" url def 
    asyncEvent <- performRequestAsync (tag (constant defaultReq) buttonEvent) 
    let rspApod = fmapMaybe (\r -> decodeXhrResponse r :: Maybe Apod) asyncEvent 
    return() 

コンパイラにそれはあなたの意図解析の目標を知るために必要な情報を与える必要があり:: Maybe Apodインライン型注釈を追加します。実際に効果があるので、この方法で型シグニチャを使用することは合理的です。

希望に役立ちます!

+0

あなたの優しい説明とあなたの解決策に感謝します。あなたの解はReidの解と同じです。残念ながら、それは助けになりません – Jogger

+0

私は 'rspApod :: Event Spider(たぶんApod)= fmap(\ r - > decodeXhrResponse r ::多分Apod)asyncEvent'を両方の側にアノテートしても、私はまだ' No 'decodeXhrResponse'の使用に起因する(aeson-0.9.0.1:Data.Aeson.Types.Class.FromJSON Apod) – Jogger

+0

私は追加の 'インスタンスFromJSON(Maybe Apod)'宣言を追加しました。私は2つのエラーがあります: 'Overlapping 'aeson-1.0.2.1:Data.Aeson.Types.FromJSON。$ gdmparseJSON''と '(aeson-0.9.0.1:Data.Aeson.Types。)のインスタンスがないため、FromJSON(おそらくApod) のインスタンスが生成されます。クラス.FromJSON Apod) ' Data.Aeson 1.0と0.9の2種類のバージョンがあるようです。これはどのように可能ですか? – Jogger

関連する問題