所以我正在为CSV文件编写一个实用函数的小玩具箱,并在整个过程中测试我手动绑定文件的函数
table' <- parseCSVFromFile filepath
但是(来自Text.CSV
)
parseCSVFromFile :: FilePath -> IO (Either parsec-3.1.9:Text.Parsec.Error.ParseError CSV)
所以我不得不写一条快速线来消除这个错误csv crap
stripBare csv = head $ rights $ flip (:) [] csv
并将其重新定义为table = stripBare table'
。在此之后,列表函数可以处理csv文件内容并且生命继续进行
(题外话:令人惊讶的是Either a b -> b
中没有直接的Data.Either
功能。所以我使用了Data.Either.rights :: [Either a b] -> [b]
)
我想做的是脱掉csv类型的工作并一次性将它绑定到句柄。像
这样的东西table = stripBare $ table' <- parseCSVFromFile filepath
但这会在(<-
)上给出一个解析错误,说我可能错过do
...然后
table = stripBare $ do table' <- parseCSVFromFile filepath
对我说,do
块中的最后一个语句必须是表达式。
我做错了什么?
作为一个单独的好奇心,我看到了here那个
以一种非常简单的方式在Haskell desugars中表示。
do
x <- foo
e1
e2
...
变成
foo >>= \x ->
do
e1
e2
我发现这很有吸引力,并尝试了下面一行,它给了我一个类型错误
*Toy> :type (parseCSVFromFile "~/.csv") >>= \x -> x
<interactive>:1:52: error:
* Couldn't match type `Either
parsec-3.1.9:Text.Parsec.Error.ParseError'
with `IO'
Expected type: IO CSV
Actual type: Either parsec-3.1.9:Text.Parsec.Error.ParseError CSV
* In the expression: x
In the second argument of `(>>=)', namely `\ x -> x'
In the expression:
(parseCSVFromFile "~/.csv") >>= \ x -> x
答案 0 :(得分:0)
代码如
head $ rights $ flip (:) [] csv
很危险。您利用head
的偏好来隐藏csv
可能是Left something
的事实。我们可以将其重写为
= head $ rights $ (:) csv []
= head $ rights [csv]
= case csv of
Left _ -> error "Left found!"
Right x -> x
通常最好直接在Left
IO块中处理do
情况。类似于:(伪代码跟随)
foo :: String -> IO ()
foo filepath = do
table' <- parseCSVFromFile filepath
case table' of
Left err -> do
putStrLn "Error in parsing CSV"
print err
moreErrorHandlingHere
Right table -> do
putStrLn "CSV loaded!"
use table