haskell - comonad 是否适合为 Wumpus 世界建模?

标签 haskell comonad wumpus-world

我正在尝试寻找 comonad 的一些实际应用,并且我想尝试看看是否可以将经典的 Wumpus 世界表示为 comonad。

我想使用此代码让 Wumpus 在世界中左右移动并清理脏瓷砖并避免坑。似乎唯一有用的 comonad 函数是 extract(获取当前图 block ),而移动和清理图 block 则不能使用扩展或重复。

我不确定 comonads 是否合适,但我看过一个演讲 ( Dominic Orchard: A Notation for Comonads ),其中使用 comonads 在二维矩阵中对光标进行建模。

如果 comonad 是代表 Wumpus 世界的好方法,您能告诉我我的代码哪里出错了吗?如果错了,您能否建议一个简单的 comonads 应用程序?

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

谢谢!

最佳答案

我会将我的一系列评论移至更连贯的答案..

你拥有的实际上是一个“ zipper ”,特别是用于列表的 zipper

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

与所有 zipper 一样,ListZip 有一个焦点,我们可以在这个焦点区域上开展工作

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

我们可以移动焦点,即您所说的 moveLeftmoveRight

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

现在像所有 zipper 一样,ListZip 是一个共同点!

extract 提取焦点,或者当前占据的方 block

instance Comonad ListZip where
  extract = focus

extend返回一个新世界,我们根据“规则”修改了每个聚焦的方 block 。

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

本例中的规则是一个函数

ZipList a -> a

如果这让您隐约想起元胞自动机,那么您是对的!这与康威的生命游戏等游戏的工作方式非常相似:简单的上下文相关规则。

我们还定义了duplicate,它将返回ListZipListzip,其中焦点已向每个可能的方向移动ListZip

现在我不知道这在 Wumpus 的背景下到底有什么用处,是否可以对板上的每个方 block 进行统一的转换?将 Wumpus 世界具体化为所有可能的 Wumpus 世界的 Wumpus 世界,您能从中受益吗?

这就是 comonads 在本例中为您提供的内容。

关于haskell - comonad 是否适合为 Wumpus 世界建模?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24073674/

相关文章:

monads - Comonad 的精辟总结。 (单子(monad)是 'type for impure computation' )

list - 从理论上讲,这是列表的有效comonad 实例吗?

prolog - 如何将文件中的数据读入Prolog

haskell - 理解涉及 Left、Right 和 case 语句的示例

haskell - 在 Haskell 中管理有状态的计算系统

variables - 我如何记住 Haskell 中二叉搜索树的根

haskell - 如何将附加参数传递给 Control.Monad.Reader 实例

haskell - Comonads 或 Representable 上的镜头