我如何处理很多级别的缩进? [英] How do I deal with many levels of indentation?
问题描述
main = do
inFH< p> - openFile...ReadMode
outFH< - openFile...WriteMode
forM myList $ \ item - >
...
if ...
then ...
else else
...
case ... of
Nothing - > ...
只需x - >做
...
...
代码很快飞到对,所以我想把它分成几块,例如使用 where
子句。问题是,这些 ...
中的许多都包含读/写语句给两个句柄 inFH
和 outFH
,并使用,其中
语句将会在上下文之外呈现这两个名称。我必须在每次使用 where
语句时发送这两个变量。
有没有更好的方法处理这个问题?在很多情况下,这些深度嵌套的缩进是深度嵌套错误检查的结果。如果这对你有帮助,你应该看看 MaybeT
及其大哥哥 ExceptT
。这些提供了一种干净的方式,可以将我们做什么假设一切正确的代码与我们在出现问题时做了什么代码分开。在你的例子中,我可能会写:
data CustomError = IfCheckFailed | MaybeCheckFailed
main = handleErrors< =< runExceptT $ do
inFH< - liftIO $ openFile ...
outFH< - liftIO $ openFile ...
for myList $ \\ \\item - > (...)(throwError IfCheckFailed)
...
x< - liftMaybe MaybeCheckFailed ...
...
liftMaybe :: MonadError em => e - >也许是 - > m a
liftMaybe err = maybe(throwError err)return
handleErrors :: CustomError a - > IO a
handleErrors(Left err)=大小写错误
IfCheckFailed - > ...
MaybeCheckFailed - > ...
handleErrors(正确成功)=返回成功
请注意,我们仍然会增加缩进在 forM
循环中;但其他检查在 main
中in-line完成,并在 handleErrors
。
I am writing a script that has a very logically complicated loop:
main = do
inFH <- openFile "..." ReadMode
outFH <- openFile "..." WriteMode
forM myList $ \ item ->
...
if ...
then ...
else do
...
case ... of
Nothing -> ...
Just x -> do
...
...
The code soon flies to the right, so I was thinking breaking it into pieces, using for example where
clauses. The problem is, many of these ...
contain reading/writing statements to the two handles inFH
and outFH
, and using a where
statement will render those two names out of context. I would have to send in these two variables everytime I use a where
statement.
Is there a better way of dealing with this?
In many cases, these deeply-nested indentations are the result of deeply-nested error checking. If that's so for you, you should look into MaybeT
and its big brother ExceptT
. These offer a clean way to separate the "what do we do when something went wrong" code from the "what do we do assuming everything goes right" code. In your example, I might write:
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
Notice that we still increase indentation at the forM
loop; but the other checks are done "in-line" in main
, and are handled all at the same indentation level in handleErrors
.
这篇关于我如何处理很多级别的缩进?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!