无法将预期类型'Bool'与实际类型'Int'匹配

the*_*lim 0 haskell functional-programming

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
Run Code Online (Sandbox Code Playgroud)

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

Wil*_*sem 7

你写下你的代码:

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
Run Code Online (Sandbox Code Playgroud)

我在这里用粗体表示一个案例,但错误适用于所有这些案例.你写作条件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
Run Code Online (Sandbox Code Playgroud)

所以现在我们有了布尔值,程序将编译,但它仍然是语义上的.平均值是元素之和除以元素数量.元素的数量是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
Run Code Online (Sandbox Code Playgroud)

现在它有效,但它仍然不优雅:它需要五名警卫来检查条件的数量,总共十二次比较.因此,这将是相当低效的.

一个更好的想法可能是转换True1False0,我们可以用这样做bool catamorphism功能:bool :: a -> a -> Bool -> a.如果我们建造它像bool 0 1那么我们有一个转换功能False0,并True1,我们就可以写这样的:

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
Run Code Online (Sandbox Code Playgroud)

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