Найдите слово в двумерном лабиринте, используя монаду State

Если у нас есть доска 4x4 с символами (которые могут повторяться) и какое-то случайное слово, нам нужно найти, можно ли найти это слово на доске. Теперь эту проблему довольно легко решить, не используя никаких причудливых вещей. Но с точки зрения обучения, как можно подойти к этой проблеме, когда мы должны учитывать следующие вещи:

  • доска постоянна и не собирается меняться, поэтому допустим, что мы заинтересованы в использовании Reader для нее
  • при поиске слова нам нужно сохранить набор посещенных плиток на доске, поэтому, скажем, мы заинтересованы в использовании для него состояния.

Первая идея заключалась в том, чтобы использовать что-то вроде этого:

findWord :: String -> Position -> ReaderT Board (State (S.Set Position)) -> Bool

input String — это оставшаяся часть слова, которое мы ищем

где Position (Int, Int) используется для определения того, где мы сейчас находимся на доске (и Set хранит, какие позиции мы посетили во время этого пути поиска)

Доска просто хранит информацию о символах в каждой позиции, для простоты ее можно представить как [[Char]]

возврат Bool предназначен для использования в качестве окончательного результата, чтобы сказать, содержит ли доска слово или нет

поиск на доске можно производить во всех направлениях (включая диагонали); слово не должно быть ни на горизонтальной линии, ни на диагональной линии - пока символы слова соединены на доске - решение верно.

Теперь о самой проблеме: если мы используем состояние для решения этой проблемы, как мы можем гарантировать, что функция вернется, как только слово будет найдено, и не продолжит поиск других путей? Например, если слово, которое мы ищем, — «ААААА», а поле — это просто 16 символов «А», то функция должна возвращаться примерно через 5 итераций и не продолжать поиск всех возможных путей (поскольку количество успешных пути огромны)?

Я ищу несколько советов о том, как решить эту проблему, используя одно обязательное ограничение: использование монады State. Ценна любая информация, будь то совет, псевдокод или даже работающее решение. Спасибо.


person ksaveljev    schedule 06.07.2014    source источник


Ответы (1)


Вместо того, чтобы возвращать Bool, могу ли я предложить использовать другую монаду в стеке преобразователя с явной возможностью сокращения вычислений, например. Maybe:

findWord :: String -> Position -> ReaderT Board (StateT (S.Set Position) Maybe) ()

Я думаю, что это правильная точка в стеке, чтобы он автоматически возвращал состояние после каждого сбоя.

Теперь вы можете использовать msum (из класса MonadPlus), который будет проверять каждую опцию в списке по очереди и (для стека на основе Maybe) останавливаться на первой подопции, которая успешна, или давать сбой всей msum, если ни одна из них не подходит. Например. что-то вроде

msum $ map (findWord remainingString) listOfNeighboringPositions
person Ørjan Johansen    schedule 06.07.2014
comment
Большое спасибо, msum сработало чудесно. Узнал что-то новое. Получил все работает. Еще раз спасибо! - person ksaveljev; 07.07.2014