Haskell从URL读取CSV报错:ByteString版本冲突问题求助
Haskell读取URL中CSV数据遇ByteString版本冲突问题
我刚学Haskell24小时,已经初步理解语法,但觉得它比Python复杂不少。尝试多种方法并查阅文档后,还是没法从URL读取CSV数据,怀疑是ByteString库的问题,代码如下:
{-# LANGUAGE OverloadedStrings #-} import Network.HTTP.Conduit (simpleHttp) import Data.Csv import qualified Data.ByteString.Lazy as BL import qualified Data.Vector as V readCSV :: String -> IO (Either String (V.Vector BL.ByteString)) readCSV url = do csvData <- simpleHttp url return $ decode HasHeader csvData main :: IO () main = do let url = "https://earthquake.usgs.gov/fdsnws/event/1/query?format=csv&starttime=2023-12-30&endtime=2023-12-31&minlatitude=32&maxlatitude=42&minlongitude=-124&maxlongitude=-114&minmagnitude=3" result <- readCSV url case result of Left err -> print err Right csv -> print csv
运行后报错信息:
• Couldn't match expected type ‘BL.ByteString’ with actual type ‘bytestring-0.11.5.3:Data.ByteString.Lazy.Internal.ByteString’ NB: ‘BL.ByteString’ is defined in ‘Data.ByteString.Lazy.Internal’ in package ‘bytestring-0.12.0.2’ ‘bytestring-0.11.5.3:Data.ByteString.Lazy.Internal.ByteString’ is defined in ‘Data.ByteString.Lazy.Internal’ in package ‘bytestring-0.11.5.3’ • In the second argument of ‘decode’, namely ‘csvData’ In the second argument of ‘($)’, namely ‘decode HasHeader csvData’ In a stmt of a 'do' block: return $ decode HasHeader csvData | 11 | return $ decode HasHeader csvData
问题原因
这个错误是ByteString库版本冲突导致的:项目依赖的bytestring是0.12.0.2版本,但network-conduit(或其依赖)使用的是0.11.5.3版本,两个版本的ByteString类型属于不同的包实例,编译器无法匹配。
解决方法
- 统一依赖版本:在项目的
cabal.project或stack.yaml中强制指定bytestring版本,让所有依赖统一使用同一个版本。比如用Cabal的话,在cabal.project中添加:
若0.11.5.3版本兼容性更好,也可以指定该版本。constraints: bytestring == 0.12.0.2 - 清理并重构项目:执行
cabal clean && cabal build(Cabal环境)或stack clean && stack build(Stack环境),清除旧构建缓存后重新编译。 - 排查依赖树:用
cabal list --installed bytestring或stack ls dependencies查看已安装的依赖版本,确认冲突的具体来源。
额外优化建议
当前代码返回的是原始CSV行的V.Vector BL.ByteString,如果想解析成具体的业务数据类型,可以定义数据类型并实现FromRecord实例,示例如下:
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} import Network.HTTP.Conduit (simpleHttp) import Data.Csv import qualified Data.ByteString.Lazy as BL import qualified Data.Vector as V import GHC.Generics -- 定义地震数据类型,字段需和CSV表头对应 data Earthquake = Earthquake { time :: String , latitude :: Double , longitude :: Double , mag :: Double -- 对应CSV中的"mag"字段 } deriving (Show, Generic) -- 自动生成FromRecord实例 instance FromRecord Earthquake readCSV :: String -> IO (Either String (V.Vector Earthquake)) readCSV url = do csvData <- simpleHttp url return $ decode HasHeader csvData main :: IO () main = do let url = "https://earthquake.usgs.gov/fdsnws/event/1/query?format=csv&starttime=2023-12-30&endtime=2023-12-31&minlatitude=32&maxlatitude=42&minlongitude=-124&maxlongitude=-114&minmagnitude=3" result <- readCSV url case result of Left err -> print err Right csv -> V.mapM_ print csv
这样就能直接解析出CSV中的具体字段,比原始ByteString更易处理。
内容的提问来源于stack exchange,提问作者Hafid Traikzi
相关产品推荐
相关产品推荐

