无法将预期类型"布尔"与实际类型"Int"匹配


howManyAboveAverage :: Int -> Int -> Int -> Int
howManyAboveAverage a b c
| a && b && c >= m = 3
| a && b >= m = 2
| b && c >= m = 2
| a && c >= m = 2
| a || b || c >= m = 1
| otherwise = 0
where m = a + b + c

请问为什么这段代码没有运行,我收到很多我不明白的错误

你在代码中写道:

howManyAboveAverage :: Int -> Int -> Int -> Int
howManyAboveAverage a b c
| a && b && c >= m = 3
| a && b >= m = 2
| b && c >= m = 2
| a && c >= m = 2
| a || b || c >= m = 1
| otherwise = 0
where m = a + b + c

我在这里用粗体显示一个案例,但错误适用于所有案例。你写作为条件a && b && c >= m.对于Haskell来说,这意味着你像a && b && (c >= m)一样写它。现在(&&)是一个运算符,它将两个布尔值作为操作数,并计算这两个操作数的逻辑和。但操作数不是布尔值。c >= m是布尔值,但ab不是布尔值。

所以我们必须在所有操作数上写条件,例如:

howManyAboveAverage :: Int -> Int -> Int -> Int
howManyAboveAverage a b c
| a>= m&& b>= m&& c >= m = 3
| a>= m&& b >= m = 2
| b>= m&& c >= m = 2
| a>= m&& c >= m = 2
| a>= m|| b>= m|| c >= m = 1
| otherwise = 0
where m = a + b + c

所以现在我们有布尔值,程序将编译,但它在语义上仍然是不连贯的。平均值是元素的总和除以元素的数量。这里的元素数是 3,所以我们应该把它除以 3。由于除以一个数字会导致数值错误,并且意味着我们必须在浮点世界中工作,因此将我们与之比较的元素乘以 3 更安全,因此:

howManyAboveAverage :: Int -> Int -> Int -> Int
howManyAboveAverage a b c
|a3>= m  &&b3>= m  &&c3>= m = 3
|a3>= m  &&b3>= m = 2
|b3>= m  &&c3>= m = 2
|a3>= m  &&c3>= m = 2
|a3>= m  ||b3>= m  ||c3>= m = 1
| otherwise = 0
where m = a + b + c
a3 = 3 * a
b3 = 3 * b
c3 = 3 * c

现在它可以工作,但仍然不优雅:它需要五个警卫来检查条件的数量,总共十二个比较。因此,这将相当低效。

更好的主意可能是将True转换为1False转换为0,我们可以使用bool函数来做到这一点:bool :: a -> a -> Bool -> a。如果我们像bool 0 1一样构造它,那么我们有一个函数,可以将False转换为0True转换为1,然后我们可以这样写:

import Data.Bool(bool)
howManyAboveAverage :: Int -> Int -> Int -> Int
howManyAboveAverage a b c =booltoint (3*a >= m)
+ booltoint (3*b >= m)
+ booltoint (3*c >= m)
where m = a + b + c
booltoint = bool 0 1

它可以进一步改进,但我把它留作一个练习。

&&运算符的类型为Bool -> Bool -> Bool。这意味着必须Bool两个操作数,结果也是一个Bool

例如,在表达式a && b >= m中,右操作数(b >= m)是Bool,但左操作数(a)不是-它是一个Int

所以这就是为什么你得到一个错误:左操作数也需要是一个Bool

最新更新