如何在Haskell中实现forking try catch?
我想写一个函数如何在Haskell中实现forking try catch?,haskell,try-catch,fork,Haskell,Try Catch,Fork,我想写一个函数 forkos_try :: IO (Maybe α) -> IO (Maybe α) 它接受一个命令xx是一个命令式操作,它首先改变状态,然后检查该状态是否混乱。(它不做任何外部操作,这需要某种操作系统级别的沙箱来恢复状态。) 如果x的计算结果为Just y,forkos\u try返回Just y 否则,forkos\u try回滚状态,并返回Nothing 在内部,它应该fork()进入线程parent和child,并在child上运行x 如果x成功,child
forkos_try :: IO (Maybe α) -> IO (Maybe α)
它接受一个命令x
x
是一个命令式操作,它首先改变状态,然后检查该状态是否混乱。(它不做任何外部操作,这需要某种操作系统级别的沙箱来恢复状态。)
- 如果
的计算结果为x
,Just y
返回forkos\u try
Just y
- 否则,
回滚状态,并返回forkos\u try
Nothing
fork()
进入线程parent
和child
,并在child
上运行x
- 如果
成功,x
应继续运行(返回child
的结果),而x
应死亡parent
- 否则,
应继续运行(返回父级
),而无
应死亡子级
x
)位于外部库中,不能在线程之间传递。因此,哪个线程保持活动状态的语义非常重要
形式上,“keep running”的意思是“执行一些continuationrest::Maybeα->IO()
”。但是,该延续在代码中没有任何明确的地方
就我的情况而言,我认为(目前)使用forkOS
(需要整个计算child
才能运行)以不同的风格编写它是可行的,因为我可以为rest
编写一个显式表达式。但是,困扰我的是,我不知道如何使用原语函数forkOS
——人们会认为它足够通用,可以支持任何特定的情况(它可以作为高级API出现,比如forkOS\u try
)
编辑——如果问题仍然不清楚,请查看带有显式rest
的示例代码[]
p、 我已经有一段时间没有写并发代码了;希望我对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等)。有些事情是无法扭转的(发射导弹、写信给stdout等等),所以我在这里看到了两种选择之一:
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)
tryIO::ios->(s->IO())->IO(可能是a)->IO(可能是a)
tryIO save restore action=do
initialState>不返回任何内容
Just x->return(Just x)
在这里,您必须提供一些数据结构
s
,以及将save
保存到所述数据结构并从中restore
的方法。这使您可以灵活地执行任何必要的克隆。(例如,save
可以将某个文件复制到临时位置,然后restore
可以将其复制回并删除临时文件。或者save
可以复制某些IOREF的值,然后restore
可以将该值放回。)这种方法可能不是最有效的,但是它非常简单。这里是一个新手实现,它有一个明确的延续:我很难理解您的问题。状态似乎在IO单子中,但您希望回滚-因为这通常无法完成(例如,可能您发射了一些导弹),如何回滚状态?我认为OP希望使用操作系统级别的fork(即,不是forkIO
)。这将允许您回滚所有内部状态,如IORef
s。当然,它不能回滚写入文件的内容。@gatoatigrado如果使用forkOS,您的解决方案将非常繁重(例如,子进程必须启动新的IO管理器和其他运行时服务)。既然您只想改变状态,您是否考虑过使用ST
monad?这允许您拥有状态,但不要求您处于IO中。注意:forkOS
不是fork()
。也许你的意思是?对不起,我用粗体字说,s
不能在线程之间传递;特别是,它也不能转换为Haskell类型。这是C库中存在的一些状态。注意:forkOS
只是启动一个线程,就像forkIO
,但绑定到一个新的操作系统级线程。要分叉这个过程,您需要@gatoatigrado我建议的解决方案是单线程的,所以这不是问题。但是你没有办法拍下这个状态?如果您希望能够回滚,那么这将是一个相当大的问题。除了求助于进程分叉之外,没有其他手段是一种非常强烈的代码气味。@DanBurton,是的,求助于进程分叉是不明智的