我正在编写一个逻辑上非常复杂的循环的脚本:
main = do
inFH <- openFile "..." ReadMode
outFH <- openFile "..." WriteMode
forM myList $ \ item ->
...
if ...
then ...
else do
...
case ... of
Nothing -> ...
Just x -> do
...
...
该代码很快就会向右移动,因此我正在考虑使用
where
子句将其分成几部分。问题是,其中许多...
包含对两个句柄inFH
和outFH
的读/写语句,并且使用where
语句会使这两个名称脱离上下文。每当我使用where
语句时,我都必须发送这两个变量。有没有更好的方法来解决这个问题?
最佳答案
在许多情况下,这些深度嵌套的缩进是深度嵌套的错误检查的结果。如果是这样,您应该研究MaybeT
及其兄弟ExceptT
。这些提供了一种清晰的方法,可以将“出现问题时我们该怎么办”代码与“假定一切都正确的情况下我们应该做什么”代码分开。在您的示例中,我可能会这样写:
data CustomError = IfCheckFailed | MaybeCheckFailed
main = handleErrors <=< runExceptT $ do
inFH <- liftIO $ openFile ...
outFH <- liftIO $ openFile ...
forM myList $ \item -> do
when (...) (throwError IfCheckFailed)
...
x <- liftMaybe MaybeCheckFailed ...
...
liftMaybe :: MonadError e m => e -> Maybe a -> m a
liftMaybe err = maybe (throwError err) return
handleErrors :: Either CustomError a -> IO a
handleErrors (Left err) = case err of
IfCheckFailed -> ...
MaybeCheckFailed -> ...
handleErrors (Right success) = return success
注意,我们仍然在
forM
循环中增加缩进;但是其他检查是在main
中“内联”完成的,并且都在handleErrors
中以相同的缩进级别进行处理。
关于haskell - 如何处理许多级别的压痕?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33005903/