Haskell类型不匹配问题:Text无法匹配Double如何修复?
修复Haskell中JSON解析的类型不匹配错误
咱们直接戳中问题核心:你定义的WeatherValues类型里,temp_min字段是Double类型,但getTempMin函数返回的是Text——这就是触发Couldn't match expected type ‘Double’ with actual type ‘Text’错误的根本原因。另外,Prelude.read: no parse错误大概率是之前尝试用read强制转换Text到Double失败留下的痕迹,核心还是类型不匹配的问题。
具体修复方案
方案1:修正手动解析的类型逻辑
先调整getTempMin的返回类型和错误处理,让它直接返回Double(因为JSON里的temp_min是数值,Aeson可以直接解析成Double,不需要转成Text):
getTempMin :: Object -> Double getTempMin info = fromMaybe (error "Failed to parse temp_min") $ parseMaybe extractTempMin info where extractTempMin = \info -> info .: "main" >>= \mainInfo -> mainInfo .: "temp_min"
这里用fromMaybe处理解析失败的情况,如果parseMaybe返回Nothing就抛出错误(你也可以改成返回Maybe Double,让上层逻辑处理错误,这样更健壮)。
接着同步修正WeatherValues的其他字段类型(JSON里的temp_max、pressure、speed都是数值,都应该设为Double),并补全对应解析函数:
data WeatherValues = WeatherValues { temp_min :: Double , temp_max :: Double , pressure :: Double , speed :: Double } deriving (Show) extractValues :: BSL.ByteString -> WeatherValues extractValues rawJSON = case decode' rawJSON of Nothing -> error "Invalid JSON!" Just info -> WeatherValues (getTempMin info) (getTempMax info) (getPressure info) (getWindSpeed info) -- 补全其他字段的解析函数,逻辑和getTempMin一致 getTempMax :: Object -> Double getTempMax info = fromMaybe (error "Failed to parse temp_max") $ parseMaybe extractTempMax info where extractTempMax = \info -> info .: "main" >>= \mainInfo -> mainInfo .: "temp_max" getPressure :: Object -> Double getPressure info = fromMaybe (error "Failed to parse pressure") $ parseMaybe extractPressure info where extractPressure = \info -> info .: "main" >>= \mainInfo -> mainInfo .: "pressure" getWindSpeed :: Object -> Double getWindSpeed info = fromMaybe (error "Failed to parse wind speed") $ parseMaybe extractWindSpeed info where extractWindSpeed = \info -> info .: "wind" >>= \windInfo -> windInfo .: "speed"
方案2:用Aeson自动推导解析(更优雅)
你已经开启了DeriveGeneric扩展,完全可以让Aeson自动处理JSON解析,省去手动写解析函数的麻烦:
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} module PrepareAnswer where import Control.Monad import Data.Maybe import GHC.Generics import Data.Aeson import Data.Aeson.Types import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import Data.Text import Network.HTTP.Client import Text.Read import AskWeather -- 字段名和JSON键完全对应,Aeson会自动匹配 data WeatherValues = WeatherValues { temp_min :: Double , temp_max :: Double , pressure :: Double , speed :: Double } deriving (Show, Generic) -- 自动推导JSON解析实例 instance FromJSON WeatherValues where parseJSON = genericParseJSON defaultOptions extractValues :: BSL.ByteString -> WeatherValues extractValues rawJSON = case decode' rawJSON of Nothing -> error "Invalid JSON!" Just val -> val prepareAnswer :: Response BSL.ByteString -> Text prepareAnswer response = Data.Text.pack . show $ weatherValues where weatherValues = extractValues . responseBody $ response
这种方式下,Aeson会自动识别JSON里的数值字段,解析成Double类型,完美解决类型不匹配问题。
错误根源复盘
- 你把
getTempMin的返回类型设为Text,但JSON里的temp_min是数值类型,Aeson解析后得到的是Double,强行塞到Text返回值里(用字符串当默认值)导致类型冲突。 - 当你把Text类型的结果传给要求
Double的WeatherValues字段时,就触发了类型不匹配的编译错误。
内容的提问来源于stack exchange,提问作者Ashot Bes
相关产品推荐
相关产品推荐

