我正试图编写一个递归函数,将数字列表相加,并返回总和是否可被5整除的Bool
。然而,我不能让它发挥作用。
div5 :: [Int] -> Bool
div5 (x:xs)
| total `mod` 5 == 0 = True
| otherwise = False
where
total = total + x
表达式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等效值(。我把这个留作练习。