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
请问为什么这段代码没有运行,我有很多错误,我不明白
答案 0 :(得分:6)
您在代码中写道:
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
是布尔值,但a
和b
不是布尔值。
所以我们必须在所有操作数上编写条件,如:
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
所以现在我们有布尔,程序将编译,但它仍然在语义上是incorect。平均值是元素之和除以元素数。元素的数量是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
转换为1
和False
转换为0
,我们可以使用bool
catamorphism < / em>功能:bool :: a -> a -> Bool -> a
。如果我们像bool 0 1
那样构建它,那么我们有一个将False
转换为0
,True
转换为1
的函数,然后我们就可以这样写:< / p>
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
答案 1 :(得分:3)
&&
运算符的类型为Bool -> Bool -> Bool
。这意味着两个操作数必须为Bool
,结果也为Bool
。
例如,在表达式a && b >= m
中,右操作数(b >= m
)是Bool
,但左操作数(a
)不是 - 它是一个Int
。
这就是你收到错误的原因:左操作数也必须是Bool
。