haskell - 如何在 Haskell 中实现 fork try-catch?

标签 haskell try-catch fork

我想写一个函数

forkos_try :: IO (Maybe α) -> IO (Maybe α)

它接受命令x。 x 是一个命令式操作,它首先改变状态,然后检查该状态是否困惑。 (它不会执行任何外部操作,这需要某种操作系统级沙箱来恢复状态。)

  • 如果 x 计算结果为 Just yforkos_try 返回 Just y
  • 否则,forkos_try回滚状态,并返回Nothing

在内部,它应该fork()到线程parentchild中,x上运行> child

  • 如果 x 成功,child 应继续运行(返回 x 的结果),而 parent 应终止
  • 否则,parent 应继续运行(返回 Nothing),而 child 应死亡

问题:如何编写具有与 forkos_try 等效或更强大语义的内容? 注意-- 状态突变(由x)位于外部库中,并且无法在线程之间传递。因此,保持哪个线程事件的语义很重要。

正式地,“继续运行”意味着“执行一些延续rest::Maybe α -> IO ()”。但是,该延续并未在代码中明确保留。

对于我的情况,我认为(暂时)可以使用 forkOS 以不同的风格编写它(这需要运行整个计算 child) ,因为我可以为 rest 编写一个显式表达式。但是,令我困扰的是,我无法弄清楚如何使用原始函数 forkOS 来做到这一点——人们会认为它足够通用以支持任何特定情况(这可能会表现为一种高-级别 API,如 forkos_try)。

编辑 - 如果问题仍然不清楚,请参阅带有显式 rest 的示例代码 [ http://pastebin.com/nJ1NNdda ].

附:我已经有一段时间没有写并发代码了;希望我对 POSIX fork() 的了解是正确的!提前致谢。

最佳答案

如果你明确地对状态进行建模,事情就会变得更容易推理。

someStateFunc :: (s -> Maybe (a, s))

-- inside some other function
case someStateFunc initialState of
  Nothing -> ... -- it failed. stick with initial state
  Just (a, newState) -> ... -- it suceeded. do something with
                            -- the result and new state

对于不可变状态,“回滚”很简单:只需继续使用 initialState 即可。而且“不回滚”也很简单:只需使用 newState 即可。

所以...我从你的解释中假设这个“外部库”执行一些不平凡的 IO 效果,但这些效果仅限于一些已知且可逆的操作(修改文件、IORef 等)。有些事情是无法逆转的(发射导弹、写入标准输出等),所以我在这里看到两个选择之一:

  1. 克隆世界,并在沙箱中运行 Action 。如果成功,则继续在现实世界中运行该操作。
  2. 克隆世界,并在现实世界中运行 Action 。如果失败,则用您之前拍摄的快照替换现实世界。

当然,这两者实际上都是同一个做法:fork the world。一个世界负责行动,另一个世界不负责。如果行动成功,那么那个世界就会继续;否则,另一个世界仍将继续。您建议通过构建 forkOS 来实现此目的,这将克隆程序的整个状态,但这不足以处理例如文件修改等问题。请允许我建议一种更接近简单的不可变状态的方法:

tryIO :: IO s -> (s -> IO ()) -> IO (Maybe a) -> IO (Maybe a)
tryIO save restore action = do
  initialState <- save
  result <- action
  case result of
    Nothing -> restore initialState >> return Nothing
    Just x  -> return (Just x)

这里您必须提供一些数据结构s,以及一种从所述数据结构保存恢复的方法。这使您可以灵活地执行您认为必要的任何克隆。 (例如,save可以将某个文件复制到临时位置,然后restore可以将其复制回来并删除临时文件。或者save可以复制某些 IORef 的值,然后 restore 可以将值恢复。)这种方法可能不是最有效的,但非常简单。

关于haskell - 如何在 Haskell 中实现 fork try-catch?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9497195/

相关文章:

haskell - 通过动态函数列表传输数据

haskell - 神经网络总是为任何输入产生相同/相似的输出

haskell - 具有定义的键顺序的字典类型

java - 如何在 finally block 中输出变量?

php - 如何正确地 fork 一个开源库?

c++ - setitimer 信号似乎只在 fork 之后才有效

haskell - monad 和宏有什么区别?

java - XPath 异常处理中未执行 Catch 语句

javascript - try-catch 返回变量为未定义

c - 如何多次写入/读取管道