我正在尝试在Haskell中编写一个简单的程序。它基本上应该并行运行两个shell命令。这是代码:

import System.Cmd
import System.Exit
import Control.Monad

exitCodeToBool ExitSuccess = True
exitCodeToBool (ExitFailure _) = False

run :: String -> IO Bool
run = (fmap exitCodeToBool) . system

main = liftM2 (&&) (run "foo") (run "bar")

但是命令"foo"返回ExitFailure,我希望"bar"永远不会运行。事实并非如此!它们都运行,并且都在控制台上显示错误。

与此同时

False && (all (/= 0) [1..])

评价很好;这意味着不计算第二个参数。如何在我的应用程序中对系统命令执行相同操作?

有帮助吗?

解决方案

我认为使用 && 因为条件执行是一个坏习惯。当然,这样做只是一个理由问题 无副作用False && all (/=0) [1..], 但是当有副作用的时候,让它们以这种隐藏的方式依赖是相当混乱的。(因为这种做法非常普遍,大多数程序员会立即认识到它;但我不认为这是我们应该鼓励的东西,至少在Haskell不会。)

你想要的是一种表达方式:"执行一些操作, 直到 一个产量 False".

对于你的简单例子,我只是明确地做到这一点:

main = do
   e0 <- run "foo"
   when e0 $ run "bar"

或短: run "foo" >>= (`when` run "bar").

如果你想更广泛地使用它,最好以更一般的方式来做。简单地检查布尔条件不是很一般,你通常也想传递某种结果。传递结果是我们使用monad进行IO的主要原因,而不是简单的原始操作列表。

啊哈,莫纳德!事实上,你需要的是IO monad,但有一个额外的"杀死开关":要么你做一系列动作,每个动作都可能有一些结果传递,或者-如果其中任何一个失败–你中止整个事情。听起来很像 Maybe, ,对吧?

http://www.haskell.org/hoogle/?hoogle=MaybeT

import Control.Monad.Trans.Maybe

run :: String -> MaybeT IO ()
run s = MaybeT $ do
   e <- system s
   return $ if exitCodeToBool e then Just () else Nothing

main = runMaybeT $ do
   run "foo"
   run "bar"

其他提示

You say that you want to run commands in parallel and run "bar" only if "foo" succeeds. It makes no sense. You have to decide, if you want to run it in parallel or sequential.

If you want run "bar" only if "foo" succeed, try:

import System.Process

main = do callCommand "foo"
          callCommand "bar"

Or if you want to run it in parallel, try:

import System.Process
import Control.Concurrent


myForkIO :: IO () -> IO (MVar ())
myForkIO io = do
    mvar <- newEmptyMVar
    forkFinally io (\_ -> putMVar mvar ())
    return mvar

main = do mvar <- myForkIO $ callCommand "foo"
          callCommand "bar"
          takeMVar mvar

The IO action

liftM2 f action1 action2

runs both actions for any binary function f is (e.g., (&&) in your case). If you want to just run action1 you can code it as follows:

--| Short-circuit &&
sAnd :: IO Bool -> IO Bool -> IO Bool
sAnd action1 action2 = do
    b <- action1
    if b then action2 else return False

Use it as sAnd action1 action2.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top