表达式where total = total + x没有多大意义,它会在计算时导致无限循环,因为你说total等价于total + x,因此(total + x) + x、((total + x) + x) + x等.
一个简单的解决方案是利用sum :: (Foldable f, Num a) => f a -> a对数字求和,然后检查结果是否等于0:
div5 :: (Foldable f, Integral a) => f a -> Bool
div5 xs = mod (sum xs) 5 == 0
或无点表示法:
div5 :: (Foldable f, Integral a) => f a -> Bool
div5 = (0 ==) . (`mod` 5) . sum
例如:
Prelude Data.List> div5 [1,4,2,5]
False
Prelude Data.List> div5 [1,4,2,5,3]
True
这不仅适用于列表,也适用于所有Foldable 类型,例如Maybe、Tree 等。
但是,如果值非常大,或者元素的数量非常大,这会给出不正确的结果,因为这样总和就不能再用数字类型表示了。但是我们不需要计算全和,我们可以先计算每个元素的(`mod` 5),然后将其相加,再将每个和为mod 5,然后得到和的结果mod 5,从而我们可以检查这是否为 0:
import Data.List(foldl')
div5 :: (Foldable f, Integral a) => f a -> Bool
div5 xs = foldl' f 0 xs == 0
where f y = (`mod` 5) . (y+) . (`mod` 5)
您可以将其转换为带有辅助函数的递归函数,该函数执行递归以求和值(或它们的模块 5 等效项)。我把它留作练习。