从Haskell程序中的堆栈溢出或堆耗尽中恢复

Jur*_*yra 5 stack-overflow haskell exception

我目前在Haskell中编写遗传算法,其中我的染色体是代表可执行系统的相当复杂的结构.

为了让我评估染色体的适应性,我必须运行一个evolution执行给定系统的一个计算周期的函数.然后通过计算evolution在系统中没有变化之前可以应用多少次来计算适应度(在这种情况下系统终止).

现在的问题如下:一些系统可以无限长时间运行并且永远不会终止 - 我想惩罚那些(通过给予它们很少的分数).我可以简单地对步骤数量设置一定的限制,但它不能解决另一个问题.

我的一些系统执行指数计算(即使对于它们增长到巨大尺寸的渐变步骤的小值)它们也会导致ERROR - Control stack overflow.对于人类观察者来说,很明显它们永远不会终止,但算法无法知道它是如何运行和粉碎的.

我的问题是:是否有可能从这样的错误中恢复?我希望我的算法在遇到这个问题后继续运行,并相应地调整染色体分数.

在我看来,最好的解决方案就是告诉程序:"嘿,试试这个,但如果你失败了就不要担心.我知道如何处理它".但是我甚至不确定这是否可能.如果没有 - 还有其他选择吗?

Don*_*art 5

从Haskell内部很难可靠地做到这一点 - 尽管在某些条件下GHC会为这些条件引发异常.(你需要GHC 7).

import Control.Exception
Run Code Online (Sandbox Code Playgroud)

如果你真的只想捕获堆栈溢出,这是可能的,如下例所示:

> handle (\StackOverflow -> return Nothing) $
              return . Just $! foldr (+) 0 (replicate (2^25) 1) 
Nothing
Run Code Online (Sandbox Code Playgroud)

或者捕获任何异步异常(包括堆耗尽):

> handle (\(e :: AsyncException) -> print e >> return Nothing) $
              return . Just $! foldr (+) 0 (replicate (2^25) 1) 
stack overflow
Nothing
Run Code Online (Sandbox Code Playgroud)

但是,这很脆弱.

或者,使用GHC标记,您可以在GHC编译的进程上强制执行最大堆栈(或堆)大小,如果超过这些限制则会导致它被终止(GHC似乎没有最近的堆栈限制).

如果使用GHC编译Haskell程序(如建议的那样),则将其运行为:

$ ghc -O --make A.hs -rtsopts 
Run Code Online (Sandbox Code Playgroud)

强制执行以下低堆限制:

$ ./A +RTS -M1M -K1M
Heap exhausted;
Run Code Online (Sandbox Code Playgroud)

这需要GHC.(同样,你不应该使用Hugs进行这类工作).最后,您应该首先通过GHC中的分析来确保您的程序不会使用过多的堆栈.