干净地替换当前Haskell进程(exec)

干净地替换当前Haskell进程(exec),haskell,exec,Haskell,Exec,我正在编写一个Haskell程序,其唯一目的是在收集一些信息以确定该程序应使用哪些参数执行后,执行另一个(非Haskell)程序 使用executeFile替换正在运行的Haskell进程非常容易,但是我想知道是否有办法确保Haskell程序在被替换之前正确地清理掉它 例如,Control.Exception.finally通常有助于确保即使发生异常也能执行清理操作,但如果我们执行一个完全不同的流程,它将无效: module Main (main) where import Control.E

我正在编写一个Haskell程序,其唯一目的是在收集一些信息以确定该程序应使用哪些参数执行后,执行另一个(非Haskell)程序

使用
executeFile
替换正在运行的Haskell进程非常容易,但是我想知道是否有办法确保Haskell程序在被替换之前正确地清理掉它

例如,
Control.Exception.finally
通常有助于确保即使发生异常也能执行清理操作,但如果我们执行一个完全不同的流程,它将无效:

module Main (main) where

import Control.Exception    (finally)
import System.Posix.Process (executeFile)

main = finally (do putStrLn "opening file descriptors"
                   putStrLn "writing temporary files"
                   executeFile "ls" True [] Nothing)
               (putStrLn "cleaning up")
上面的示例永远不会打印“清理”


是否有一种“干净”执行此操作的推荐方法?

您需要将
可执行文件
放在
最后
之后,因为它完全替换Haskell程序中的任何代码

main = do
    finally (putStrLn "opening" >> putStrLn "writing") (putStrLn "cleaning up")
    executeFile "ls" True [] Nothing

executeFile
中唯一可能出现的异常是exec本身存在问题,但您必须继续执行,就好像exec可以工作一样,并且您不会回到Haskell代码;这是一个单向的
goto
,不是一个子程序调用。

关于这一点Haskell没有什么特别的。如果你想在一个过程完成后再做一些事情,你不能只是/完成它。您必须改为/,然后在父级中对子级执行/并在返回后执行清理



编辑:以上内容将在新流程完成后进行清理。如果你不在乎这一点,只想在Haskell完成但新流程仍在运行时进行清理,那么chepner的答案就行了。

你的最后一段似乎不正确;如果
exec
系统调用失败,那么
executeFile
会抛出一个异常,该异常可以像其他异常一样被捕获。只有当
exec
syscall成功,但新程序出现问题时,才不会返回。是的,但当时大概没有什么需要清理的了。您可以捕获异常,可能会记录为什么
ls
没有运行,但是在运行
ls
之前应该完成的任何其他操作都需要已经完成。