6

我正在使用 Haskell 编写一个 shell 脚本,turtle并且想知道编写可能失败的命令的最佳实践。

现在我有一个案例表达式楼梯,如下所示:

runRemote :: MonadIO io => Text -> Text -> io ()
runRemote oldVersion' newVersion' = sh $ do
  mkdir "out"
  e1 <- shell ("command " <> oldVersion') empty
  case e1 of
    ExitFailure n -> cleanup 
    ExitSuccess -> do
      e2 <- shell ("command " <> newVersion') empty
      case e2 of
        ExitFailure n -> cleanup 
        ExitSuccess -> do
          curDir <- pwd
          cd (curDir <.> oldVersion')
          e3 <- shell ("command something else") empty
          case e3 of
           -- ...
           -- And so on...

如果case表达式在Maybe类型上进行扩展,解决方案将是派生一个Monad实例。

库作者是否有特殊原因尚未为其派生Monad实例,ExitCode或者是否有更好的方法来对 Haskell shell 代码进行错误处理?

4

3 回答 3

5

一种替代方法是使用(.&&.)and (.||.)fromTurtle.Prelude

(.&&.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode

类似于&&Bash

仅当第一个命令返回时才运行第二个命令ExitSuccess

(.||.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode

类似于||Bash

仅当第一个命令返回时才运行第二个命令ExitFailure

它们允许您像这样链接您的命令(请注意,所涉及的所有内容都必须返回一个ExitCode,包括清理):

(command1 .&&. command2) .||. cleanup

或者,如果您在每种情况下都需要不同的清理操作:

(command1 .||. cleanup1) .&&. (command2 .||. cleanup2)

顺便说一句,值得注意的是,在moduleExitCode中不是由turtle 而是由baseSystem.Exit定义的。

于 2015-10-20T02:35:28.923 回答
2

ExitCode不是单子,也不是单子转换器。一个 monad 需要一个类型参数,一个 monad 转换器需要两个。ExitCode不需要。现在假设我们暂时忽略这个不那么小的问题。你能想出一个有意义的解释吗

join :: ExitCode (ExitCode a) -> ExitCode a

是的,我也不能。您可以合理地争辩说shell应该生成Either FailureCode (),或者可能在 中工作ExceptT FailureCode IO,但是库作者可能认为这对于这项工作来说太混乱或不灵活。

于 2015-10-19T23:54:01.367 回答
1

您可以使用MaybeT这种方式避免楼梯:

{-# LANGUAGE OverloadedStrings #-}

import Turtle
import Control.Monad.Trans
import Control.Monad.Trans.Maybe

check io = do ec <- lift io
              MaybeT $ case ec of
                         ExitSuccess -> return (Just True)
                         _           -> return Nothing

checkShell a b = check (shell a b)

main = do
  dostuff
  putStrLn "cleaning up"

dostuff = runMaybeT $ do
  checkShell "date" empty
  checkShell "/usr/bin/false" empty
  checkShell "pwd" empty
于 2015-10-20T00:28:41.640 回答