6

我想总结一个压缩列表。

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.
4

3 回答 3

6

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

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

请注意,您实际上并不需要检查这些==[]情况,因为zipWith返回[]的是那些情况,并且sum [] == 0.

averageGrade :: [Float] -> [Int] -> Float
averageGrade a b = sum (zipWith (\ x y -> x * fromIntegral y) a b)
于 2019-11-14T09:21:41.460 回答
2

您可以(*)使用不同的类型,因为它们是Num类型类的成员。您可以在类型签名中添加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
于 2019-11-14T09:24:59.863 回答
1

替代实现:

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]
于 2019-11-14T10:45:58.400 回答