从[1 ..]的地图中排除计算结果?

时间:2011-05-31 11:24:06

标签: list haskell infinite fold

我目前正在开发一个计算友好对的程序(Project Euler Problem 21)。我已经找到了解决方案,但是我注意到我的程序中的一个缺陷就是它会评估集合[1 ..]的所有数字,无论我们是否已经找到了这个数字。

即。如果当前评估220和284被发现是它的对,但是当地图函数达到284时继续进行它不应该再次评估它。

import Data.List

properDivisors :: (Integral a) => a -> [a]
properDivisors n = [x | x <- [1..n `div` 2],
                        n `mod` x == 0 ]

amicablePairOf :: (Integral a) => a -> Maybe a
amicablePairOf a
    | a == b = Nothing
    | a == dOf b = Just b
    | otherwise = Nothing
        where dOf x = sum (properDivisors x)
              b = dOf a

getAmicablePair :: (Integral a) => a -> [a]
getAmicablePair a = case amicablePairOf a of
            Just b -> [a,b]
            Nothing -> []


amicables = foldr (++) [] ams
    where ams = map getAmicablePair [1..]

举个例子:

take 4 amicables

返回:

[220,284,284,220]

我是Haskell和函数式编程的新手,如果它是一个明显的解决方案,请原谅我。

2 个答案:

答案 0 :(得分:5)

您的问题是,您尝试通过输出两个友好数字来安全工作。但实际上,你并不安全,因为你的功能仍然计算两个数字,无论它们是否友好。为什么不这样做:

import Data.List

divSum :: (Integral a) => a -> [a]
divSum n = sum (filter (\a -> a `mod` n == 0) [1..n `div` 2])

isAmicable :: (Integral a) => a -> Bool
isAmicable a = a /= b && a == c where
  b = divSum a
  c = divSum b

amicables = filter isAmicable [1..]

答案 1 :(得分:2)

或许getAmicablePair稍作修改有帮助吗?

getAmicablePair :: (Integral a) => a -> [a]
getAmicablePair a = case amicablePairOf a of
            Just b -> if a < b then [a,b] else []
            Nothing -> []

...所以你只需要一个较小的第一个元素