考虑下一段代码:
data Tile = EmptyTile | X | O data Player = Player1 | Player2 instance Show Tile where show EmptyTile = " " show X = "X" show O = "O" data Board = (Tile, Tile, Tile, Tile, Tile, Tile, Tile, Tile, Tile) emptyBoard :: Board emptyBoard = (EmptyTile,EmptyTile,EmptyTile,EmptyTile,EmptyTile,EmptyTile,EmptyTile,EmptyTile,EmptyTile) instance Monad Board where return x = x f >>= x = x
我希望那个董事会成为一个单子.但问题是我得到以下错误 -
[1 of 1] Compiling Main ( Main.hs, Main.o ) Main.hs:17:14: error: Illegal binding of built-in syntax: (,,,,,,,,)
需要进行哪些更改才能将Board作为monad进行定义
每一个data
构造函数必须有一个明确的名称,比如你用了EmptyTile
,X
,O
,Player1
和Player2
.有Board
,没有这样的名字; 哈斯克尔认为这是荒谬的
data Board = (,,,,,,,,) Tile Tile Tile Tile Tile Tile Tile Tile Tile
所以在这里,(,,,,,,,,)
将是"构造函数名称",但这在Haskell中实际上并不合法,因此错误.
只需选择一个自定义名称,如无聊
data Board = Board Tile Tile Tile Tile Tile Tile Tile Tile Tile
现在,这不可能是一个monad:monad最重要的是一个仿函数,即在该参数中对某种类型和协变进行参数化的东西.你可以把它变成一个monad,通过用Tile
多态的东西替换那些硬编码的字段:
data Board t = Board t t t t t t t t t deriving (Functor)
但是Applicative
和Monad
实例看起来比你提出的要多一些.
您可能会考虑这样的方法:Board
您可以定义索引类型,而不是手动滚动数据结构:
data BoardIndex = Edge0 | Middle | Edge1 type Board t = (BoardIndex, BoardIndex) -> t
那么这将是一个没有任何进一步定义的monad,即函数monad,它具有你可能想要的语义.它往往效率有点低,因为结果实际上并没有存储但总是在现场重新计算,但对于像Tic Tac Toe这样的东西几乎不重要.(通过引入备忘录,您可以在以后轻松提高效率.)