How to convert monadic list function to width search?

I just got over the hump to figure out how to use the list monad to do non-deterministic calculations. However, I believe that my algorithm will benefit from a breadth-first search instead of the first one you get from the List monad.

Here is a snippet showing an interesting part of my algorithm. This is the solver for the Akari logic puzzle.

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 

Basically, he applies some basic deterministic rules to see if this allows this decision. If he is not trying to put light in different places. If the light makes the puzzle inconsistent after recursing to solve it, it places an exception mark in which the light was and continues to be. If he finds solutions when placing lights, then he adds them to the list of solutions.

This works fine, but slower, because often there is an obvious choice for which speculation is coordinated, which quickly leads to an inconsistent puzzle and allows you to place x with only one (or two) search levels, but if it does not select this coordination until then until halfway through the search, then she will first start chewing a bunch of uninteresting things. So the idea is to search in width.

I have googled things like "the breadth of the first monarchy of uncertainty", and I get several results that are hard for me to understand, for example:

  • Control.Monad.Omega This seems redundant for what I need, because it protects against infinitely divergent determinism, which for me is not so, and I do not quite understand it.

  • The Control.Monad.WeightedSearch docs for Control.Monad.Omega suggest using this instead when using it as Monad, but I think the weighting also went a little too far for my needs. I probably have only 2 weights, one for things with solutions and one for things that have no solutions.

  • Control.Monad.Level I do not believe that this will work for what I want, since only the leaves of the tree matter.

  • Data.Tree I think this may be what I want to use, but I'm not sure how to convert my list of monadic code to use it, although I feel that there is a beautiful way.

My next question will be how to parallelize it :)

+6
source share
1 answer

I believe that the “Backtracking, Interleaving and Terminating Monad Transformers” (functional gem) of Kiselev, Shan and Friedman describes the solution.

Disclaimer: I am not an expert in this work!

Basically, you should use a different monad. Since the ListT monad transformer does depth - at first, they came up with the new LogicT monad LogicT , which makes the width first. (If you are not interested in monad transformers, you can simply apply the transformer to Id to return the normal monad).

First, they recognize the flaws in other approaches:

a simple depth search performed by most MonadPlus implementations is unfair: the non-deterministic choice between the two alternatives tries each solution from the first alternative before any solution from the second alternative. When the first alternative offers an infinite number of solutions, the second alternative has never been tried, making the search incomplete. Indeed, as our examples in section 3 show, a fair retreat helps to stop more logical programs.

[...]

The second flaw in many existing backrex monks is the adoption of the Prologue cut, which mixes negation with cropping. Theoretically, each of the negatives and truncations independently makes logical programming languages ​​more expressive

[...]

A third practical flaw is the often forgotten top-level interface: how to run and interact with a calculation that can return an infinite number of answers? The most common solution is to provide a stream that can be consumed or processed at the top level as desired. But in the case of monad transformers, this solution only works if the base monad is not strict (for example, the nuns Haskells lazy list and LazyST). In the case of a strict base monad, the estimation may diverge, forcing to evaluate the entire flow, even if we need only one answer.

They then present a solution based on the LogicT monad transformer LogicT msplit function. Although the code link is broken, I searched Hoogle for LogicT and found this .

I hope that reading this article will give you good experience in this topic and help you understand how to use the projects that you have already found.

If you find this article useful, be sure to check out its links and other documents that cite it!

+6
source

All Articles