在 Haskell 中移动棋子

Moving piece across a board in Haskell

我正在 Haskell 玩国际象棋游戏,我正在努力移动我的棋子。

我知道在函数式编程中,一切都应该是不可变的,但我认为我真的需要更新的片段列表。我查看了 monad.state,但我很难理解它。

这是我的作品清单:

piecesList::[Piece]
piecesList = [Piece _type _color _coords, ..., ... Piece _type _color _coords]

以及我将一块从 (old_x,old_y) 移动到 (new_x,new_y) 的方法:

但是,我的作品列表似乎还没有更新。

我接近它了吗?如果是这样,我错过了什么?还是我的做法完全错误?

谢谢!

编辑

我正在使用以下类型:

data Piece = Piece {
  _type :: PieceType,
  _color :: PieceColor,
  _position :: Position
} deriving Eq

data PieceColor = Black | White deriving Eq
data PieceType = Rook | Knight | Bishop | King | Queen | Pawn deriving Eq
type Position = (Int, Int)

it looks like my list of pieces is not updated.

当然不是:就像 Haskell 中的所有内容一样,片段列表是 不可变的 ,因此它在任何情况下都不会改变。

piecesList = updateBoard (index_of a b ) moved

您只需定义一个 new 件列表,它也恰好被称为 pieces。 GHCi 和 IHaskell 允许这种 shadowing(Haskell 本身不允许!),但这只是意味着您在 之后定义的任何东西 指的是 piecesList 将使用新版本。但是 getPieceindex_of 已经在此“更新”之前定义,并且完全没有注意到您以后选择提出的任何新定义。

完成此类任务的最直接方法是显式传递 游戏状态的修改版本。事实上 updateBoard 已经通过给出整个 [Piece] 列表作为结果朝着那个方向发展。但是您还需要在下一步中 使用 更新后的状态,而不是再次使用起始状态 piecesList。基本上,如果您将 pieces 作为 参数 传递给 getPieceindex_ofupdateBoard,您将完成任务.

updateBoard :: Int -> Piece -> [Piece] -> [Piece] -- You don't seem to need `Maybe`

请注意,此签名被解析为

updateBoard :: Int -> Piece -> ([Piece] -> [Piece])

现在,有点尴尬,必须显式地为各种辅助函数赋予相同的旧值。您已经提到了 state monad,这确实是这里使用的标准。本质上,状态 monad 做完全相同的事情:将一个值作为参数传递给子函数。唯一的区别是,如果没有另外说明,它 自动使用始终相同的值 .

您将签名更改为

import Control.Monad.State
updateBoard :: Int -> Piece -> State [Piece] ()

在这里,State [Piece] () 只是 [Piece] -> ([Piece], ()) 的新类型包装器。 () 表示除了更新状态之外,您没有提供任何有趣的结果信息。您也可以提供其他信息,并且确实需要在getPiecesindexOf中提供:

getPiece :: Int -> State [Piece] Piece
indexOf :: (Int,Int) -> State [Piece] Int

现在关于所有内容的实际书写方式:do 符号有帮助。只需将结果放在末尾的return中,并用get获取旧状态。例如,

getPiece :: Int -> State [Piece] Piece
getPiece a = do
   piecesList <- get
   return $ piecesList!!a

新状态可以简单地“put进入monad”:

updateBoard :: Int -> Piece -> State [Piece] ()
updateBoard index newPiece = do
    piecesList <- get
    let (x,_:ys) = splitAt index piecesList
    put $ x ++ newPiece : ys