在 Haskell 中将整数除以整数

3

我希望有一个函数,可以从给定的成绩列表中计算平均分。这是我目前编写的代码:

getAverageRate :: [Int]->Int
getAverageRate marks = (fromIntegral (foldr (+) 0 marks))/(fromIntegral (length marks))

我尝试使用'foldr'获取列表中所有分数的总和,然后除以'length marks'。尽管我已经使用了'fromIntegral',但仍出现错误,我找不到问题所在。
No instance for (Fractional Int) arising from a use of `/'
Possible fix: add an instance declaration for (Fractional Int)
In the expression:
  (fromIntegral (foldr (+) 0 marks)) / (fromIntegral (length marks))
In an equation for `getAverageRate':
    getAverageRate marks
      = (fromIntegral (foldr (+) 0 marks))
        / (fromIntegral (length marks))

通过调用 fromIntegral,您正在请求将 Int 转换为其他类型。但是通过将函数的返回类型限制为 Int,您正在费力地将这些 Int 转换为的类型是... Int - Daniel Wagner
1个回答

8

事实上,Int 表示整数,因此将其除以其他数字并不合理,因为大多数情况下除法的结果不是整数。

幸运的是,我们有 div,它代表整数除法,所以你可以这样做:

 average :: [Int] -> Int
 average [] = error "Can't average an empty list"
 average xs = sum xs `div` length xs

如果您不想使用整数除法,那么我们可以进行如下操作:

 average :: [Int] -> Double
 average xs = fromIntegral (sum xs) / fromIntegral (length xs)

这段代码将所有东西都提升为类型进行除法计算。

最后,您可以选择一种舍入方法并使用已有的数值。

 average xs = round $ fromIntegral (sum xs) / fromIntegral (length xs)

友情提示,sum函数是有问题的,会使用foldl而不是foldl',所以在处理大型列表时,请务必使用-O2编译。


1
作为一个新手,我为什么要认为 sum 函数是邪恶的? - devshorts
3
@devshorts 这是基于foldl的,但在一些情况下可能会出现堆栈溢出的问题。使用 -O2 可以解决这个问题,可以搜索 foldlfoldl' 的区别。 - daniel gratzer
抱歉自我推销一下,但对于Haskell初学者,这里有一个描述为什么foldl'foldl更好的内容。 - J. Abrahamson
2
@J.Abrahamson 我觉得你忘记了一个链接?我很想有一个好的教程可以指引,所以请分享 :) - daniel gratzer
2
哦,我做了:https://dev59.com/aGIj5IYBdhLWcg3wWT6c#20359256 谢谢你通知我。 - J. Abrahamson
我还要补充一点,对于无符号整数,最好使用quotrem而不是divmod - 它们由于不同的符号处理方法而稍微更快。 - Yuuri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接