Haskell 哈斯克尔:如何修复;类型变量“ambigous”;编译器错误?
我使用的是GHCJSi,版本0.2.0-7.10.3:和Reflection dom库版本0-4(来自)。我没有使用Hackage中的reflect-dom-0.3 以下Haskell程序未使用Reflect-dom-0.4编译:Haskell 哈斯克尔:如何修复;类型变量“ambigous”;编译器错误?,haskell,reflex,Haskell,Reflex,我使用的是GHCJSi,版本0.2.0-7.10.3:和Reflection dom库版本0-4(来自)。我没有使用Hackage中的reflect-dom-0.3 以下Haskell程序未使用Reflect-dom-0.4编译: {-# LANGUAGE RecursiveDo, ScopedTypeVariables, DeriveGeneric, OverloadedStrings #-} import Reflex import Reflex.Dom import Data.Aeson
{-# 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
)。我将类型签名从JSON a=>XhrResponse->maybea
更改为没有类型变量的签名XhrResponse->maybea 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
{-#语言递归DO,ScopedTypeVariables,DeriveGeneric,重载字符串#-}
输入反射
导入reflection.Dom隐藏(decodeXhrResponse,decodeText)
--导入反射.Dom
导入数据.Aeson
进口GHC.仿制药
导入符合条件的数据。文本为T
进口管制
将限定数据.ByteString.Lazy导入为BL
导入Data.Text.Encoding
数据Apod=Apod{版权::T.文本
,日期::T.Text
,解释::T.文本
,hdurl::T.Text
,媒体类型::T.文本
,服务版本::T.文本
,title::T.Text
,url::T.Text
}派生(通用、显示)
来自JSON Apod的实例
main::IO()
main=do
mainWidget$el“div”$do
按钮无Xhr响应->可能是
解码XhrResponse::XhrResponse->可能是Apod
decodeXhrResponse=加入。fmap解码文本_xhrResponse\u responseText
--内联和更改的库函数:
--decodeText::FromJSON a=>T.Text->可能是a
解码文本::T.文本->可能是Apod
解码文本=解码。基本法。编码UTF8
我试图为rspApod添加一个作用域类型变量,如rspApod::Event t Apod
或rspApod::Event Spider Apod
,但没有帮助
问题:
如何更改第一个程序才能成功编译?(内联和更改库函数是一个非常糟糕的技巧!)
为什么编译器没有找到并使用数据类型
Apod
的FromJSON
实例?因此函数的原始签名是
decodeXhrResponse::FromJSON a=>XhrResponse->Maybe a
因此,在使用时,编译器需要为给定的a
从JSON中找到实例。在您的例子中,a
是Apod
,因此编译器应该对Apod
的FromJSON
实例进行微调。在您的代码中,编译器无法知道这是您的意图。这是解析时的常见问题,需要告诉编译器目标类型应该是什么
现在您可能会争辩说,它应该能够通过周围的代码(如asyncEvent
)来确定目标类型,但这不是出于某种原因。可能是周围的代码也是通用的。考虑下面的场景:
main=print$read x
编译器如何知道读取x
的目标类型
read::reada=>String->a
显然,这不会通知它目标
print::Show a=>a->IO()
这只是断言a
必须有一个Show
实例
a
太泛型,无法解析,我们需要一个具体类型
因此,当内联函数并将类型签名更改为包含Apod
时,您为编译器提供了所需的信息,让编译器知道从JSON
实例中查找什么内容
下面是我如何解决这个问题的:
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 ()
main::IO()
main=do
mainWidget$el“div”$do
buttonEvent因此函数的原始签名是
decodeXhrResponse::FromJSON a=>XhrResponse->Maybe a
因此,在使用时,编译器需要为给定的a
从JSON
中找到实例。在您的例子中,a
是Apod
,因此编译器应该对Apod
的FromJSON
实例进行微调。在您的代码中,编译器无法知道这是您的意图。这是解析时的常见问题,需要告诉编译器目标类型应该是什么
现在您可能会争辩说,它应该能够通过周围的代码(如asyncEvent
)来确定目标类型,但这不是出于某种原因。可能是周围的代码也是通用的。考虑下面的场景:
main=print$read x
编译器如何知道读取x
的目标类型
read::reada=>String->a
显然,这不会通知它目标
print::Show a=>a->IO()
这只是断言a
必须有一个Show
实例
a
太泛型,无法解析,我们需要一个具体类型
因此,当内联函数并将类型签名更改为包含Apod
时,您为编译器提供了所需的信息,让编译器知道从JSON
实例中查找什么内容
下面是我如何解决这个问题的:
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 ()
main::IO()
main=do
mainWidget$el“div”$do
按钮事件(\r->decodexhresponse r)
~>decodexhresponse
您的原始程序不明确。仅仅添加一个类型签名decodexhresponse r::Maybe Apod
@Reid:谢谢,但是更改为let rspApod=fmapMaybe(\r->decodexhresponse r::Maybe Apod)asyncEvent
并不能解决问题:为相同的提供了一个实例。不幸的是…这似乎很难相信…在添加类型批注后,在上面发布完整错误。(\r->decodexhresponse r)
~>decodexhresponse
您的原始程序不明确。只添加一个类型签名如何decodeXhrResponse r::Maybe