IO monad的逻辑和严格性

时间:2014-04-11 12:38:38

标签: haskell logical-operators strictness

我正在尝试在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..])

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

3 个答案:

答案 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