2

I'm currently working on a board evaluator in haskell. I'm trying to use map with a function with multiple parameters; I've read other SO questions regarding this but keep getting type errors so perhaps I'm just misunderstanding the Haskell types (I'm a Python programmer). Either way, here's the code:

scorePiecesRow [] _ = 0
scorePiecesRow (x:xs) y
    | x == y            = 1 + (scorePiecesRow xs y)
    | x == '-'          = 0 + (scorePiecesRow xs y)
    | otherwise         = -1 + (scorePiecesRow xs y)

scorePieces [] _ = 0
scorePieces board y =  foldr (+) 0 (map (scorePiecesRow y) board)

scorePiecesRow works just fine when I pass it anything like "wwwb--" 'w' (which returns 3), but as soon as I call scorePieces (e.g. scorePieces ["www", "bb-"] 'w' which should return 1), I get a bunch of type errors:

<interactive>:37:14:
    Couldn't match expected type `Char' with actual type `[Char]'
    In the expression: "www"
    In the first argument of `scorePieces', namely `["www", "bb-"]'
    In the expression: scorePieces ["www", "bb-"] 'w'

<interactive>:37:21:
    Couldn't match expected type `Char' with actual type `[Char]'
    In the expression: "bb-"
    In the first argument of `scorePieces', namely `["www", "bb-"]'
    In the expression: scorePieces ["www", "bb-"] 'w'

<interactive>:37:28:
    Couldn't match expected type `[Char]' with actual type `Char'
    In the second argument of `scorePieces', namely 'w'
    In the expression: scorePieces ["www", "bb-"] 'w'
    In an equation for `it': it = scorePieces ["www", "bb-"] 'w'

I'm a bit confused by the error messages. The first one tells me, for example, that it's expecting Char, but the first argument of scorePiecesRow takes [Char]. If anyone could shed some light on this, it would be greatly appreciated!

4

2 回答 2

4

虽然 Haskell 会为您推断类型,但它们通常对于编写代码(以机器检查的方式!)和检查您的假设都非常有价值。我们可以在这里做 Haskell 的类型推理引擎的工作来弄清楚我们对这些函数的了解。

由于scorePiecesRow被添加到一个数字中,1 + (scorePiecesRow xs y)我们知道结果必须在类型类Num中(定义在哪里(+)

scorePiecesRow :: Num a => ... -> a

此外,通过查看参数中的模式匹配,我们可以很容易地看到第一个参数必须是一个列表。

scorePiecesRow :: Num a => [b] -> ... -> a

并且由于我们将第一个参数的元素与第二个参数的元素进行比较,(==)我们知道它们必须是相同的类型并且在类型类Eq中(定义在哪里(==)!)。

scorePiecesRow :: (Num a, Eq b) => [b] -> b -> a

最后,将第一个参数的元素与等于 进行比较'-',因此我们知道它们实际上必须是Char。因为String是同义词,[Char]我们可以推测它。

scorePiecesRow :: (Num a) => String -> Char -> a

我们可以做同样的事情scorePieces来学习

scorePieces :: Num a => String -> String -> a

这就是我们看到问题的地方。您正在打电话scorePieces ["www", "bb-"] 'w',即 a [String]and a CharwhilescorePieces期望 a Stringand another String

该错误准确地告诉您这一点,但这有点令人困惑,因为String[Char]是相同的,并且 GHC 在报告错误时倾向于将类型简化为最简单的形式。

于 2013-11-08T02:01:32.803 回答
1

因为将 a和 ascorePiecesRow作为其参数,所以当您在 map 函数中调用时,Haskell 决定它必须是 type ,因为它是作为 的第一个参数给出的。[Char]CharscorePiecesRow yy[Char]scorePiecesRow

这是第三条错误消息的来源,因为 Haskell 期望 a [Char],但你给它 a Char

前两个本质上是相同的,因为它scorePiecesRow y需要 a Char,因此,当你将这个函数映射到 时board,Haskell 期望board有 type [Char],因此当你给它一个 type 的板时它会失败[[Char]]

也许尝试以下方法:

scorePiecesRow _ [] = 0
scorePiecesRow y (x:xs)
    | x == y            = 1 + (scorePiecesRow y xs)
    | x == '-'          = 0 + (scorePiecesRow y xs)
    | otherwise         = -1 + (scorePiecesRow y xs)

scorePieces [] _ = 0
scorePieces board y = foldr (+) 0 (map (scorePiecesRow y) board)

或者,如果您想保持scorePiecesRow功能不变,

scorePieces [] _ = 0
scorePieces board y = foldr (+) 0 (map (\row -> scorePiecesRow row y) board)
于 2013-11-08T01:58:42.527 回答