Reputation: 560
If we have a board 4x4 with characters (which may repeat) and some random word we need to find if that word can be found on the board. Now this problem is rather easy to solve without using any fancy stuff. But from the learning perspective how can this problem be approached when we have these things to consider:
The first idea was to use something like this:
findWord :: String -> Position -> ReaderT Board (State (S.Set Position)) -> Bool
input String is the remaining part of the word we are searching for
where Position is (Int, Int) used for identifying where we currently are on the board (and Set stores which positions we have visited during this search path)
Board is simply storing information about chars in each position, for simplicity can be thought of as [[Char]]
returning Bool is meant to be used as a final result to say if the board contains the word or not
searching on the board can be made in all directions (so diagonals are included); the word doesn't need to be either on horizontal line or diagonal line - as long as the characters of the word are connected on the board - the solution is valid.
Now for the actual problem: if we use State to solve this problem how do we ensure that the function returns as soon as the word is found and it doesn't proceed with searching for other paths? For example if the word we are looking for is "AAAAA" and the board is simply 16 chars of "A", then the function should return after like 5 iterations and doesn't proceed with searching all possible paths (because the amount of successful paths is huge)?
I'm looking for some tips on how to approach this problem using one constraint which is a must: usage of State monad. Any information is valuable, be it some advice, some pseudocode or even a working solution. Thanks.
Upvotes: 2
Views: 142
Reputation: 18199
Instead of returning a Bool
, may I suggest using another monad in the transformer stack with the explicit ability to shortcut calculations, e.g. Maybe
:
findWord :: String -> Position -> ReaderT Board (StateT (S.Set Position) Maybe) ()
I think this is the right point in the stack to have it wind back the state after each failure automatically.
Now, you can use msum
(from the MonadPlus
class) which will test each option in the list in turn, and (for a Maybe
-based stack) halt on the first suboption which succeeds, or fail the whole msum
if none do. E.g. something like
msum $ map (findWord remainingString) listOfNeighboringPositions
Upvotes: 1