这可能是一个非常基本的 Haskell 问题,但让我们假设以下函数签名
-- helper functions
getWeatherInfo :: Day -> IO (Either WeatherException WeatherInfo)
craftQuery :: WeatherInfo -> Either QueryException ModelQuery
makePrediction :: ModelQuery -> IO (Either ModelException ModelResult)
Run Code Online (Sandbox Code Playgroud)
将上述所有内容链接到一个predict day
函数中的天真方法可能是:
predict :: Day -> IO (Maybe Prediction)
predict day = do
weather <- getWeatherInfo day
pure $ case weather of
Left ex -> do
log "could not get weather: " <> msg ex
Nothing
Right wi -> do
let query = craftQuery wi
case query of
Left …
Run Code Online (Sandbox Code Playgroud) 我正在编写一个具有非常复杂的循环的脚本:
main = do
inFH <- openFile "..." ReadMode
outFH <- openFile "..." WriteMode
forM myList $ \ item ->
...
if ...
then ...
else do
...
case ... of
Nothing -> ...
Just x -> do
...
...
Run Code Online (Sandbox Code Playgroud)
代码很快就会飞到右边,所以我想把它分成几块,使用例如where
子句.问题是,许多这些...
包含读/写语句到两个把手inFH
和outFH
,使用where
的语句将呈现这两个名字断章取义.我每次使用where
语句时都必须发送这两个变量.
有没有更好的方法来解决这个问题?
我有一个连接到数据库然后运行查询的函数。每个步骤都会产生IO (Either SomeErrorType SomeResultType)
.
在学习 Haskell 时,我真正喜欢使用 monad 和类似 monad 的原因之一Either
是能够使用 monad 函数(例如>>=
和 组合器)mapLeft
来简化对预期错误状态的大量处理。
通过阅读博客文章、Control.Monad.Trans
文档和其他关于 SO 的答案,我的期望是我必须以某种方式使用转换器/电梯从一个IO
上下文移动到另一个Either
上下文。
这个答案特别好,但我正在努力将其应用到我自己的案例中。
我的代码的一个更简单的示例:
simpleVersion :: Integer -> Config -> IO ()
simpleVersion id c =
connect c >>= \case
(Left e) -> printErrorAndExit e
(Right conn) -> (run . query id $ conn)
>>= \case
(Left e) -> printErrorAndExit e
(Right r) -> print r
>> release conn
Run Code Online (Sandbox Code Playgroud)
ExceptT …