Haskell zipWith

Haskell zipWith

我想总结一个压缩列表。

averageGrade :: [Float] -> [Int] -> Float
averageGrade [0.75 , 0.25] [6, 4] , result: 0,75*6 + 0.25*4 = 5.5 

当我进入 ghci 并执行以下操作时:

sum(zipWith (*) [0.75, 0.25] [6, 4])

我得到了我想要的。

但是在代码中我遇到了一个错误,我不知道为什么。

    averageGrade :: [Float] -> [Int] -> Float
    averageGrade a b
                | a == [] = 0
                | b == [] = 0
                | otherwise = (sum(zipWith (*) a b))

如果我想编译它,我会遇到以下失败:

Couldn't match type ‘Int’ with ‘Float’
Expected type: [Float]
  Actual type: [Int]
In the third argument of ‘zipWith’, namely ‘b’
In the first argument of ‘sum’, namely ‘(zipWith (*) a b)’
Failed, modules loaded: none.

您不能 * 两个具有不同类型的数字,例如 FloatInt。您需要显式转换其中之一,以便它们具有相同的类型(Float,在您的情况下)。

averageGrade :: [Float] -> [Int] -> Float
averageGrade a b
            | a == [] = 0
            | b == [] = 0
            | otherwise = sum (zipWith (\ x y -> x * fromIntegral y) a b)

请注意,您实际上不需要检查 ==[] 个案例,因为 zipWith returns [] 是这些案例,而 sum [] == 0.

averageGrade :: [Float] -> [Int] -> Float
averageGrade a b = sum (zipWith (\ x y -> x * fromIntegral y) a b)

您可以 (*) 不同的类型,因为它们是 Num 类型 class 的成员。您可以向类型签名添加 NumEq 约束,例如;

averageGrade :: (Num a, Eq a) => [a] -> [a] -> a
averageGrade a b | a == [] = 0
                 | b == [] = 0
                 | otherwise = sum $ zipWith (*) a b

*Main> averageGrade [0.75 , 0.25] [6, 4]
5.5

然而,正如@chi 提到的,您实际上并不需要检查空列表,因此我们实际上并不需要类型签名中的 Eq 约束。以下应该足够了。

averageGrade :: Num a => [a] -> [a] -> a
averageGrade a b = sum $ zipWith (*) a b

*Main> averageGrade [0.75 , 0.25] [6, 4]
5.5

替代实施:

averageGrade :: [Float] -> [Float] -> Float
averageGrade [] _ = 0
averageGrade _ [] = 0
averageGrade (x:xs) (y:ys) = x * y + (averageGrade xs ys)

用法:

averageGrade [1.0, 2.0] [2.0, 2.0]