Tim*_*art 5 haskell comonad wumpus-world
我试图找到一个comonad的实际应用程序,我想我会试着看看我是否可以代表经典的Wumpus世界作为一个comonad.
我想使用这个代码让Wumpus左右移动穿过世界并清理脏瓷砖并避免凹坑.似乎唯一有用的comonad函数是extract(获取当前tile)以及移动和清理tile不能使用扩展或复制.
我不确定comonad是否合适,但我看过一个谈话(Dominic Orchard: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
Run Code Online (Sandbox Code Playgroud)
谢谢!
我会把我的一系列评论移到一个更连贯的答案中.
你有什么实际上是一个"拉链",特别是拉链列表
data ListZip a = ListZip {lefts :: [a]
,focus :: a
,rights :: [a]}
Run Code Online (Sandbox Code Playgroud)
我们可以将非空列表转换为 ListZip
toZip :: [a] -> Maybe (ListZip a)
toZip (x:xs) = Just $ ListZip [] x xs
toZip _ = Nothing
Run Code Online (Sandbox Code Playgroud)
像所有拉链一样,ListZip重点突出,我们可以在这个重点领域开展工作
modifyFocus :: (a -> a) -> ListZip a -> ListZip a
modifyFocus f z = z{focus = f $ focus z}
Run Code Online (Sandbox Code Playgroud)
我们可以把重点放在你所谓的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
Run Code Online (Sandbox Code Playgroud)
现在像所有拉链一样,ListZip是一个comonad!
extract 提取焦点或当前占用的方块
instance Comonad ListZip where
extract = focus
Run Code Online (Sandbox Code Playgroud)
并extend返回一个新世界,我们根据"规则"修改了每个聚焦广场.
extend f w = ListZip (moving moveLeft) (f w) (moving moveRight)
where moving i = map f $ iterate i w
Run Code Online (Sandbox Code Playgroud)
在这种情况下,规则是一个函数
ZipList a -> a
Run Code Online (Sandbox Code Playgroud)
如果这让你想起细胞自动机,你就是对的!这与Conway的生命游戏之类的游戏非常相似:简单的上下文相关规则.
我们也得到duplicate确定,将返回Listzip的ListZip的,其中重点在每个曾经可能的方向被移动ListZip.
现在我不知道在Wumpus的背景下究竟有什么用处,你可以对你板上的每个方块进行任何统一的转换吗?能否将Wumpus世界变为Wumpus世界所有可能的Wumpus世界,您能从中受益吗?
这就是comonads在这种情况下给你的东西.
| 归档时间: |
|
| 查看次数: |
313 次 |
| 最近记录: |