Haskell 不能';t匹配类型‘;a’;与‘;区块’;在任何一种情况下

Haskell 不能';t匹配类型‘;a’;与‘;区块’;在任何一种情况下,haskell,Haskell,我正在尝试创建一个同时使用[Block]和[Ground]的函数。 为此,我声明该函数接收[a]和一个Int,该Int用作一个标志,用于保存每次调用该函数时我正在使用的其中一个列表的信息 printRow::[a]->Position->Int->[Picture] 打印行[]位置n=[] 打印行(h:t)(x,y)n | n==0=((打印块(右h)(x,y)):(打印行t(x+1,y)n)) |否则=((打印图块(左h)(x,y)):(打印行t(x+1,y)n)) printTile::块地

我正在尝试创建一个同时使用[Block]和[Ground]的函数。 为此,我声明该函数接收[a]和一个Int,该Int用作一个标志,用于保存每次调用该函数时我正在使用的其中一个列表的信息

printRow::[a]->Position->Int->[Picture]
打印行[]位置n=[]
打印行(h:t)(x,y)n | n==0=((打印块(右h)(x,y)):(打印行t(x+1,y)n))
|否则=((打印图块(左h)(x,y)):(打印行t(x+1,y)n))
printTile::块地面->位置->图片
但是,我得到了以下错误:

Gloss.hs:47:51:错误:
•无法将类型“a”与“块”匹配
“a”是一个刚性类型变量,由
以下项的类型签名:
printRow::forall a。[a] ->Position->Int->[图片]
在光泽处。hs:44:11
预期类型:块或接地
实际类型:接地
•在“printTile”的第一个参数中,即“左h”
在“(:)”的第一个参数中,即
“(打印图块(左h)(x,y))”
在表达式中:
((打印图块(左h)(x,y)):(打印行t(x+1,y)n))
•相关绑定包括
t::[a](以光泽装订。hs:46:13)
h::a(以光泽装订。hs:46:11)
printRow::[a]->位置->整数->[图片]
(以光泽装订。hs:45:1)

正如Robin Zigmond所指出的,
printRow
不能像您所说的那样一般,因为它传递给
printTile
的值必须是
块地类型,而不是任意类型的
a
。因此,函数类型必须是

printRow :: [Either Block Ground] -> Position -> Int -> [Picture]
一旦进行了此更改,就不再需要
Int
参数(无论如何,它应该是
Bool

printRow [] _ = []
printRow (h:t) (x,y) = printTile h (x, y) : printRow t (x+1,y)
但是请注意,这几乎是
zipWith
函数封装的模式:

zipWith f (x:xs) (y:ys) = f x y  : zipWith f xs ys

您要做的是对一对值调用
printTile
,一个是
块地面
,另一个是更新的位置。您可以很容易地获得无限多个位置列表,用于
[(x',y)|x'问题在于,您声明可以使用任何类型的列表调用
printRow
。但是,您将其第一个值传递给一个函数,该函数希望它是
。事实上,两个防护装置传递它的方式使得
a
既需要是
值,也需要是
地面
,因此您无法通过简单地更改
printRow
的类型签名来解决此问题。要么是实现错误,要么是
printTile
的签名错误。@RobinZigmond我认为您的评论足以回答问题事实上,
Int
参数(实际上可能是
Bool
)是不必要的,因为
printRow
应该具有type
[orb Block Ground]->Position->[Picture]
;您只需将第一个参数的每个元素直接传递给
printile
。事实上,
printRow
本质上只是
map printile
的一个变体。
printRow bgs (x,y) = zipWith printTile bgs [(x',y) | x' <- [x..]]
printRow :: Either [Board] [Ground] -> Position -> [Picture]
printRow bgs (x,y) = zipWith printTile (map which bgs) [(x',y) | x' <- [x..]]
    where which = case bgs of
              Right _ = Right
              Left _ = Left