Haskell:如何修复"类型变量ambigous"编译错误?

时间:2016-12-28 17:45:24

标签: haskell reflex

我使用的是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程序无法使用reflex-dom-0.4进行编译:

SELECT ColName
FROM TableName
ORDER BY 
 CASE WHEN ColName like '%[0-9]%' 
 THEN Replicate('0', 100 - Len(ColName)) + ColName
 ELSE ColName  END

我收到错误

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

我内联reflex-dom库函数 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. (以及decodeXhrResponse)。我将类型签名decodeText更改为没有类型变量FromJSON a => XhrResponse -> Maybe a的签名。然后程序成功编译。

XhrResponse -> Maybe Apod

我尝试为rspApod添加范围类型变量,例如{-# 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实例用于数据类型FromJSON

1 个答案:

答案 0 :(得分:3)

所以函数的原始签名是

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

因此,在使用时,编译器需要找到给定FromJSON的{​​{1}}实例。在您的情况下,aa,因此编译器应对Apod的{​​{1}}实例进行细化。在您的代码中,编译器无法知道您的意图。解析时这是一个常见问题,需要告诉编译器目标类型应该是什么。

现在你可以说它应该能够通过周围的代码来确定目标类型,例如FromJSON,但它不是出于某种原因。可能是周围的代码同样通用。请考虑以下情形:

Apod

编译器如何知道读取asyncEvent的目标类型?

main = print $ read x显然这并没有告知目标。

x这只是断言read :: Read a => String -> a必须有print :: Show a => a -> IO ()个实例。

a太通用了,无法解析,我们需要一个具体的类型。

因此,当内联函数并更改类型签名以包含Show时,您为编译器提供了查询要查找的a实例所需的信息。

以下是我将如何解决这个问题:

Apod

添加FromJSON内联类型注释应该为编译器提供了解预期解析目标所需的信息。以这种方式使用类型签名是合理的,因为它实际上是有效的。

希望有所帮助!