Haskell 没有执行所有外部 shell 命令

Haskell not executing all external shell commands

我写了这个程序并编译了:

ghc --make shell.hs

当我运行它看起来像:

$./shell
enter your number:
6
6
okay... it execute 6 time...

如果我删除 sleep 2 语句,它会快速退出但只输出 6.

我尝试按照类似问题 at this answer 给出的建议(即下面代码中的内容)进行操作,但没有成功。

似乎很奇怪,它没有执行所有的命令。我如何强制它以严格的顺序执行所有命令?懒惰是一个很好的特性,但是当涉及到 IO 时,它就很糟糕,或者我不是一个足够的专家来理解它。

我想做的是以严格的顺序执行列表中的所有命令,我不想 Haskell 到 "intelligently" 删除一些代表我的命令(如果我想在 shell 中执行 sleep 2 秒,我应该被允许这样做)。

如果必须使用waitForProcess来解决这个问题,那么我的问题是我不知道如何使用它。我试过 google 但没有看到一个简单的例子。

请注意,我想要一个适用于我在下面给出的程序代码的工作代码解决方案,并且应该合理保证该程序在 bash 运行ning 上按预期正常工作Linux(例如,Debian 7)作为下面给出的 Python 程序 运行s.

import System.Process
import System.Exit

main = do
 putStrLn "enter your number:"
 n <- getLine
 main1 (readInt n)
 putStrLn ("okay... it execute " ++ n ++" time...")

readInt:: String -> Int
readInt = read

main1 n = do
 ExitSuccess <- system ("echo " ++ (show n))
 ExitSuccess <- system "sleep 2"
 if n == 0 then (main1 (n-1)) else return ()

下面是一个 Python 程序,它可以根据需要使用适当的 sleep:

import os
for i in range(6):
  os.system("echo " + str(i))
  os.system("sleep 2")

使用 forM_ 编写更像 Python 版本怎么样:

import Control.Monad

main1 n = do
  forM_ [n,n-1 .. 1] $ \n -> do
    ExitSuccess <- system ("echo " ++ (show n))
    ExitSuccess <- system "sleep 2"
    return ()

该程序正在执行您要他执行的操作:

main1 n = do
 ExitSuccess <- system ("echo " ++ (show n))
 ExitSuccess <- system "sleep 2"
 if n == 0 then (main1 (n-1)) else return ()

这里有 n == 6,所以 if 的条件为假,然后 return () 被执行,这终止了 main1 什么都不做。

请注意,如果您传递了 n == 0,条件将为真,它将执行 main1 (-1),然后停止。在任何情况下 main1 不会 重复命令 n 次它总是执行一次(如果 n /= 0)或两次(如果 n == 0).

您可以通过以下方式解决此问题:

main1 n = do
 ExitSuccess <- system ("echo " ++ (show n))
 ExitSuccess <- system "sleep 2"
 if n > 0 then main1 (n-1) else return ()

或者,等价地:

import Control.Monad

main1 n = do
 ExitSuccess <- system ("echo " ++ (show n))
 ExitSuccess <- system "sleep 2"
 when (n > 0) $ main1 (n-1)

这里的问题是您使用一般递归来重复给定的语句。但是一般的递归可以做任何事情,所以你很容易产生错误(就像你的情况一样)。为避免这种情况,使用其他一些函数来构建代码通常很有用。例如:

main1 n = sequence_ $ map execute [1..n]

execute i = do
  ExitSuccess <- system $ "echo" ++ show i
  ExitSuccess <- system $ "sleep 2"
  return ()

或:

main1 n = mapM_ execute [1..n]

在这里你知道 mapM_[1..n] 做了什么所以结合它们告诉你 execute 动作将被执行 n 次。


在任何情况下,IO monad 保证 动作全部按顺序执行,所以你不应该将事实归因于 Haskell 懒惰代码没有执行预期的次数。

懒惰的问题和input/output不一样