首页 > 解决方案 > Haskell 递归函数返回一个布尔值

问题描述

我正在尝试编写一个递归函数来添加一个数字列表并返回Bool总和是否可被 5 整除。但是,我无法让它工作。

div5 :: [Int] -> Bool 
div5 (x:xs)  
  | total `mod` 5 == 0 = True
  | otherwise = False
  where
    total = total + x

标签: haskellrecursionpattern-matching

解决方案


这个表达式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类型,所以MaybeTree等等。

但是,如果值非常大,或者元素的数量非常大,这会给出不正确的结果,因为这样总和不再可以用数字类型表示。但是我们不需要计算全和,我们可以先计算(`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 等效项)。我把它留作练习。


推荐阅读