Haskell: How to fix the "type variable ambigous" compiler error?

Jogger

I'm using GHCJSi, version 0.2.0-7.10.3: http://www.github.com/ghcjs/ghcjs/ and the reflex-dom library version 0-4 from https://github.com/reflex-frp/reflex-dom. I'm not using reflex-dom-0.3 from Hackage.

The following Haskell program does not compile with reflex-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 ()

I get the error

 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.

I inline the reflex-dom library function decodeXhrResponse (and also decodeText). I change the type signature FromJSON a => XhrResponse -> Maybe a to a signature without a type variable XhrResponse -> Maybe Apod. Then the program compiles successfully.

{-# 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

I tried to add a scoped type variable for rspApod like rspApod :: Event t Apod or rspApod :: Event Spider Apod but it didn't help.

Questions:

How do I have to change the first program to compile successfully? (inlining and changing a library function is a very bad hack!)

Why does the compiler not find and use the FromJSON instance for the data type Apod?

Fresheyeball

So the function's original signature is

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

So when used the compiler needs to find the FromJSON instance for a given a. In your case the a is Apod, so the compiler should fine the FromJSON instance for Apod. In your code, there is no way for the compiler to know that is your intention. This is a common problem when parsing, where the compiler needs to be told what the goal type is supposed to be.

Now you could argue that it should be able to determine the goal type by the surrounding code like asyncEvent, but its not for some reason. It might be that the surrounding code is just as generic. Consider the following scenario:

main = print $ read x

How can the compiler know the target type for reading x?

read :: Read a => String -> a obviously this doesn't inform it of the target.

print :: Show a => a -> IO () and this just asserts that the a must have a Show instance.

a is too generic to be parsed to, we need a concrete type.

So when when inlined the functions and changed the type signatures to include Apod you gave the compiler the information it needs to know what FromJSON instance to look up.

Here is how I would have solved this:

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 ()

Adding the :: Maybe Apod inline type annotation should give the compiler the information it needs to know your intended parse goal. It reasonable to use type signatures in this way, since it's actually effectful.

Hope that helps!

Collected from the Internet

Please contact javaer1[email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

how to fix Ambiguous occurrence error in Haskell

How to fix indentation? Haskell: parse error on input `|'

How to fix 'declared but not used' compiler error in this simple program?

How to fix this Swift compiler error for onReceive method call?

Ionic 4 + FCM: How to fix the compiler error - colorAccent not found?

How to fix Prestashop Fatal error: Uncaught --> Smarty Compiler?

Compiler error for Haskell program not understood

This error keeps occurring in haskell any idea on how to fix it?

Error in haskell. Please guide me on how to fix this

How to fix "Couldn't match expected type" error in Haskell?

How to fix 'Non-exhaustive patterns in function' error in haskell?

How to fix parse error (possibly incorrect indentation or mismatched brackets) in Haskell

Fix for C++ Compiler Error - multiple definition

How the type `Fix` and function `fix` are same in Haskell?

How to fix palindrome function in Haskell

How to fix Kotlin compiler error inferred type is () -> Unit but Consumer<Throwable?>? was expected

How to fix error: Cygwin gcc cannot be used with --compiler=mingw32

How to fix IntelliJ IDEA 2016 TypeScript Error, "Cannot start compiler process"

How to fix the compiler error CS0009 - An attempt was made to load a program with an incorrect format?

How to fix the Java Compiler error in Android Studio when using Apache POI

I keep getting a error with this program. After getting the date in the compiler the error prompts and I'm unsure as to how to fix it

How to fix error in this emulator?

How to fix "StringIndexOutOfBoundsException" error?

Theme Error - how to fix?

How to fix this Error -npm

How to fix "not a procedure" error

how to fix locale error

how to fix error on

How to fix this error in Java?