Комонады хорошо подходят для моделирования мира Wumpus?

Я пытаюсь найти некоторые практические применения комонада, и я подумал, что я попытаюсь увидеть, смогу ли я представить классический мир Вумпуса как комонаду.

Я хотел бы использовать этот код, чтобы Wumpus мог перемещаться влево и вправо по всему миру, очищать грязные плитки и избегать ям. Кажется, что единственная полезная функция comonad - это извлечение (для получения текущей плитки), и что перемещение и очистка плиток не смогут использовать расширение или дублирование.

Я не уверен, что комонады хорошо подходят, но я видел выступление ( Доминик Орчард: Обозначение для комонад), где комонады использовались для моделирования курсора в двумерной матрице.

Если комонада является хорошим способом представления мира Wumpus, не могли бы вы показать, где мой код неверен? Если это не правильно, не могли бы вы предложить простое применение комонад?

module Wumpus where

-- Incomplete model of a world inhabited by a Wumpus who likes a nice
-- tidy world but does not like falling in pits.

import Control.Comonad

-- The Wumpus world is made up of tiles that can be in one of three
-- states.
data Tile = Clean | Dirty | Pit
  deriving (Show, Eq)

-- The Wumpus world is a one dimensional array partitioned into three
-- values: the tiles to the left of the Wumpus, the tile occupied by
-- the Wumpus, and the tiles to the right of the Wumpus.
data World a = World [a] a [a]
  deriving (Show, Eq)

-- Applies a function to every tile in the world
instance Functor World where
  fmap f (World as b cs) = World (fmap f as) (f b) (fmap f cs)

-- The Wumpus world is a Comonad
instance Comonad World where
  -- get the part of the world the Wumpus currently occupies
  extract (World _ b _) = b
  -- not sure what this means in the Wumpus world.  This type checks
  -- but does not make sense to me.
  extend f w@(World as b cs) = World (map world as) (f w) (map world cs)
      where world v = f (World [] v [])

-- returns a world in which the Wumpus has either 1) moved one tile to
-- the left or 2) stayed in the same place if the Wumpus could not move
-- to the left.
moveLeft :: World a -> World a
moveLeft w@(World [] _ _) = w
moveLeft (World as b cs) = World (init as) (last as) (b:cs)

-- returns a world in which the Wumpus has either 1) moved one tile to
-- the right or 2) stayed in the same place if the Wumpus could not move
-- to the right.
moveRight :: World a -> World a
moveRight w@(World _ _ []) = w
moveRight (World as b cs) = World (as ++ [b]) (head cs) (tail cs)

initWorld = World [Dirty, Clean, Dirty] Dirty [Clean, Dirty, Pit]

-- cleans the current tile
cleanTile :: Tile -> Tile
cleanTile Dirty = Clean
cleanTile t = t

Спасибо!

1 ответ

Решение

Я перенесу мою строку комментариев к более последовательному ответу..

То, что у вас есть, это на самом деле "молния", в частности, молния для списка

data ListZip a = ListZip {lefts   :: [a]
                         ,focus   ::  a
                         ,rights  :: [a]}

Мы можем преобразовать непустой список в ListZip

toZip :: [a] -> Maybe (ListZip a)
toZip (x:xs) = Just $ ListZip [] x xs
toZip  _     = Nothing

Как и все молнии, ListZip имеет фокус, и мы можем сделать работу в этой области

modifyFocus :: (a -> a) -> ListZip a -> ListZip a
modifyFocus f z = z{focus = f $ focus z}

И мы можем переместить фокус вокруг, что вы назвали moveLeft а также moveRight

moveLeft, moveRight :: ListZip a -> ListZip a

moveLeft  (ListZip (x:xs) y ys) = ListZip xs x (y : ys)
moveRight (ListZip xs x (y:ys)) = ListZip (x : xs) y ys

Теперь, как и все молнии, ListZip это комонада!

extract извлекает фокус или занятую площадь

instance Comonad ListZip where
  extract = focus

а также extendвозвращает новый мир, в котором мы изменили каждый сфокусированный квадрат в соответствии с "правилом".

  extend f w = ListZip (moving moveLeft) (f w) (moving moveRight)
    where moving i = map f $ iterate i w

Правило в этом случае является функцией

ZipList a -> a

Если это напоминает вам о клеточных автоматах, вы были бы правы! Это очень похоже на то, как работают такие игры, как игра жизни Конвея: простые контекстно-зависимые правила.

Мы также получаем duplicate определяется, который будет возвращать Listzip из ListZipгде фокус был перемещен в любом возможном направлении на каждом ListZip,

Теперь я понятия не имею, для чего именно это будет полезно в контексте Wumpus, есть ли какие-либо единообразные преобразования, которые вы можете сделать для каждого квадрата на вашей доске? Можете ли вы извлечь выгоду из возможности воссоединить мир Wumpus с миром Wumpus всех возможных миров Wumpus?

Вот что дают вам в этом случае комонады.

Другие вопросы по тегам