我正在Haskell玩耍,试图抓住它。我遇到了类型类问题。我想要做的是通过定义类和方法来创建一个通用的*模块,然后我尝试在程序中使用它们。我的问题是,当我尝试列出我的Box数据类型列表时,我的Board类的实例(代表地图)我收到以下错误:
Illegal instance declaration for `Board [Box]'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are type *variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Board [Box]'
我一直在谷歌搜索解决方案,但到目前为止我只找到一个页面描述了一个我在这里无法理解的解决方案:http://www.haskell.org/haskellwiki/List_instance。它描述了如何使用从上面的错误消息生成的XFlexibleInstances,但是,当我尝试使用列表中的一个元素作为Box数据类型时,我收到错误消息。
Couldn't match expected type `t' against inferred type `Box'
`t' is a rigid type variable bound by
the type signature for `!!' at <no location info>
我不知道这是否是我正在做的一些奇怪的错误,或者我的设计是不是一个好的错误。相关代码在这里:
class Tile a where
tilePosition :: a -> (Int, Int)
tileStatus :: a -> Status
棋盘类应该是一个瓦片列表(或其中的一些集合)
class Board b where
surroundingTiles :: Tile t => b -> (Int, Int) -> [t]
startingPosition :: b -> Maybe (Int, Int)
targetPosition :: b -> Maybe (Int, Int)
(!!) :: Tile t => b -> (Int, Int) -> Maybe t
这似乎是编译,但在另一个文件中,我尝试使这些类的实例是我得到错误
instance Board [Box] where
boxes !! pos = foldl (\acc b -> if boardPos b == pos then Just b else acc) Nothing boxes
...
任何正确方向的提示都将受到赞赏。
答案 0 :(得分:1)
对于[Box]
,函数!!
必须具有Tile t => [Box] -> (Int, Int) -> Maybe t
类型,这意味着每个类型t
都是Tile
的实例,您需要能够从t
获得[Box]
。
但是,您的实现类型为[Box] -> (Int, Int) -> Maybe Box
,这意味着您只能从Box
中获得[Box]
,因此无效。
你能做什么才能得到你想要的东西:
class Board b where
surroundingTiles :: Tile t => b t -> (Int, Int) -> [t]
startingPosition :: Tile t => b t -> Maybe (Int, Int)
targetPosition :: Tile t => b t -> Maybe (Int, Int)
(!!) :: Tile t => b t -> (Int, Int) -> Maybe t
instance Board [] where
...
通过这种方式,您可以使用任何Tile实例的列表作为Boards(其他任何内容的列表也是Boards,但您不能这样使用它们,因为所有函数都需要t
作为{的实例{1}})。
如果您需要说“Tiles是一块瓷砖”,而不是将所有其他列表放入Boards,您需要启用多参数类型类,这样可以让您说出以下内容:
Tile