我刚刚克服了弄清楚如何使用 List monad 进行非确定性计算的困难。但是,我相信我的算法将受益于广度优先搜索,而不是从 List monad 获得的深度优先搜索。
这是一段摘录,展示了我的算法中有趣的部分。它是逻辑谜题 Akari 的求解器。
solve :: Game -> [Game]
solve game = do
let ruleBasedSolverResult = applyRuleBasedSolversUntilSteady game
guard $ consistant ruleBasedSolverResult
if solved ruleBasedSolverResult
then return ruleBasedSolverResult
else speculate ruleBasedSolverResult
speculate :: Game -> [Game]
speculate game = do
coord <- coords game
guard $ lightableUnlit game coord
let solutions = solve $ light game coord
if null solutions
then solve $ exclude game coord
else solutions
基本上它应用一些基本的确定性规则来查看是否可以解决它。如果不是,它会尝试在不同的地方放灯。如果灯光在递归解决后使谜题不一致,则会在灯光所在和继续进行的位置放置一个排除标记。如果它在放置灯时找到了解决方案,那么它将这些解决方案添加到解决方案列表中。
这工作正常,但速度很慢,因为通常有一个明显的选择来推测哪个坐标会很快导致不一致的谜题,并让您放置一个只有一个(或两个)搜索级别的 x,但如果它没有直到搜索到一半才选择该坐标,然后它会首先咀嚼一堆无趣的东西。因此,广度优先搜索的想法。
我用谷歌搜索了诸如“广度优先非确定性单子”之类的东西,得到了一些我难以理解的结果,例如:
Control.Monad.Omega这对我需要的东西来说似乎有点矫枉过正,因为它似乎可以防止无限发散的确定性,这对我来说不是这样,而且我并不完全理解它。
Control.Monad.WeightedSearch Control.Monad.Omega 的文档建议在将其用作 Monad 时使用它,但我认为加权对于我的需求来说也有点矫枉过正。我可能只有 2 个权重,一个用于有解决方案的东西,一个用于没有解决方案的东西。
Control.Monad.Level我不相信这会为我想要的,因为只有树的叶子有值。
Data.Tree我认为这可能是我想要使用的,但我不确定如何将我的 List monadic 代码转换为使用它,尽管我觉得有一种很好的方式。
我的下一个问题是关于如何并行化它:)