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

时间:2015-08-18 18:34:22

标签: shell haskell io lazy-evaluation

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

ghc --make shell.hs

当我运行时,它看起来像是:

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

如果我删除sleep 2语句,则会快速退出但仅输出6

我尝试按照类似问题at this answer的建议(这是下面代码中的内容)但是没有用。

它没有执行所有命令似乎很奇怪。如何强制它以严格的顺序执行所有命令?懒惰是一个很好的功能,但是当谈到 IO 时,它只是糟透了,或者我不够专家来理解它。

我想要做的是按严格的顺序从列表中执行所有命令,我不希望 Haskell “智能地”代表我删除一些命令(如果我想在shell中执行sleep 2秒,我应该被允许这样做。)

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

请注意,我想为下面给出的程序代码提供一个有效的代码解决方案,应该有一个合理的保证,程序在典型的Linux(比如Debian 7)上运行的bash上按预期工作下面给出了Python 程序。

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")

2 个答案:

答案 0 :(得分:3)

如何使用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 ()

答案 1 :(得分:0)

该计划正在做你告诉他要做的事情:

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

此处我们有n == 6因此if的条件为false,然后执行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懒惰归因于代码没有被执行的事实预期的次数。

懒惰和输入/输出的问题是不同的。