Комонады хорошо подходят для моделирования мира 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?
Вот что дают вам в этом случае комонады.