我正在尝试在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..])
评价完美;这意味着不计算第二个参数。如何在我的应用程序中使用系统命令执行相同操作?
答案 0 :(得分:5)
我认为使用&&
进行条件执行是一种坏习惯。当然,对于像<{1}}这样的无副作用这样的事情来说,这只是一个理由问题,但是当有副作用时,它很容易混淆使他们以这种隐藏的方式依赖。 (因为这种做法非常普遍,大多数程序员会立即认出来;但我不认为这是我们应该鼓励的,至少在Haskell中不会。)
你想要的是一种表达方式:&#34;执行某些操作,直到一个产生False && all (/=0) [1..]
&#34;。
对于您的简单示例,我只是明确地执行此操作:
False
或简称:main = do
e0 <- run "foo"
when e0 $ run "bar"
。
如果你想更广泛地使用它,以更一般的方式做这件事是件好事。简单地检查一个布尔条件并不是很一般,你通常也想要传递某种结果。传递结果是我们使用monad进行IO的主要原因,而不仅仅是原始动作的列表。
啊哈,单身!实际上,你需要的是IO monad,但有一个额外的&#34; kill开关&#34;:你要么做一系列的动作,每个动作可能有一些结果要传递,或者 - 如果它们中的任何一个失败 - 你中止整个事情。听起来很像run "foo" >>= (`when` run "bar")
,对吧?
http://www.haskell.org/hoogle/?hoogle=MaybeT
Maybe
答案 1 :(得分:2)
您说要并行运行命令并仅在“foo”成功时运行“bar”。这没有道理。如果要并行或顺序运行,则必须决定。
如果您希望仅在“foo”成功时运行“bar”,请尝试:
import System.Process
main = do callCommand "foo"
callCommand "bar"
或者,如果您想并行运行,请尝试:
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
答案 2 :(得分:1)
IO行动
liftM2 f action1 action2
为任何二进制函数f
运行两个操作(例如,在您的情况下为(&&)
)。如果您只想运行action1
,可以按如下方式对其进行编码:
--| Short-circuit &&
sAnd :: IO Bool -> IO Bool -> IO Bool
sAnd action1 action2 = do
b <- action1
if b then action2 else return False
将其用作sAnd action1 action2
。