我有一些简单的原始操作,例如:
如果是operational monad:
import Control.Monad.Operational
type Process a = Program ProcessI a
data ProcessI a where
GetInput :: ProcessI String
Dump :: String -> ProcessI ()
getInput :: Process String
getInput = singleton GetInput
dump :: String -> Process ()
dump = singleton . Dump
或者free monad:
import Control.Monad.Free
type Process = Free ProcessF
data ProcessF a
= GetInput (String -> a)
| Dump String a
deriving (Functor)
getInput :: Process String
getInput = liftF $ GetInput id
dump :: String -> Process ()
dump s = liftF $ Dump s ()
两种情况下的简单操作都是相同的,例如:
proc1 :: Process ()
proc1 = forever $ do
a <- getInput
b <- getInput
dump $ a ++ b
dump $ b ++ a
我的问题是:是否有可能以某种方式解释进程(proc1),将某个步骤中的延续序列化为磁盘,然后在下一个程序执行期间恢复?你能举个例子吗?
如果不可能,那么最接近的解决方法是什么?
我想在下一个输入可用时启动程序,继续输入,然后解释到下一个“getInput”并退出。
我可以想象这个场景记录所有输入,然后在继续之前重放它们以使系统处于相同的状态,但在这种情况下,日志会无限制地增长。我找不到任何方法来在解释器中使用日志,因为没有可能比较continuation(没有EQ实例)并且进程是无限的。
答案 0 :(得分:5)
我认为,有两个问题:
continuation可以包含任意数据类型
continuation可以包含函数(即闭包)
特别是考虑到第二个约束,可能没有简单的方法来完全你想要的东西。
关于Can Haskell functions be serialized?的讨论指向名为packman的图书馆。从自述文件:
...该功能可用于通过记忆(跨不同程序运行)优化程序,以及检查选定位置的程序执行。两种用途都在上面链接的幻灯片组中举例说明。
(The slides它提到了,我想。)
这种方法的局限性在于,所有类型的数据都不能(或应该!)被序列化,特别是可变类型,如IORef
,MVar
和STM相关类型,有时这些最终会导致运行时异常的thunks和clos。
此外,该库依赖于由创建它的相同二进制文件占用的序列化延续,这可能是您应用程序的真正问题,也可能不是。
因此,您可以使用稍微有限且复杂的方法(例如packman
)获得您想要的更多或更少的内容,或者您可以编写自己的自定义逻辑,该自定义逻辑可以自定义类型以及捕获您关注的所有信息的自定义类型约。