【问题标题】:Understanding list comprehension in Haskell理解 Haskell 中的列表理解
【发布时间】:2013-06-01 22:08:25
【问题描述】:

这是对欧拉计划任务 #3 的剧透!如果你想自己解决,请不要继续阅读。

我正在尝试通过为 Project Euler 编写程序来学习 Haskell。目前我正在尝试解决任务 #3,它要求数字 600851475143 的最大素数。

为此,我创建了一个列表liste,其中包含所有数字,这些数字是该数字的除数(直到其平方根)。我现在的策略是,计算这些数字的除数,以确定它们是否为素数。

number = 600851475143
-- sn = sqrt number
sn = 775146

liste = [x | x <- [1..sn],  (mod number x == 0)]
-- liste = [1,71,839,1471,6857,59569,104441,486847]

primelist :: Int -> [Int]
primelist z = [y | y <- [1..z], mod z y == 0] 

main = print [primelist x | x <- liste]

应该出现在这里的结果应该是一个包含 8 个列表的列表,其中包含 liste 元素的除数。相反,列表

[[1],[1,3],[1,29],[1,3,29,87]]

被打印出来了。

如何解释这种行为?

【问题讨论】:

  • 我收到[[1],[1,71],[1,839],[1,1471],[1,6857],[1,71,839,59569],[1,71,1471,104441],[1,71,6857,486847]](GHCi 7.6.3,Linux 64 位)
  • 这很有趣......目前我正在使用 ideone,因为我在 Windows 上。那么这对他们来说似乎是一个问题。
  • 可能Int 溢出。请改用Integer。 (我只是在验证溢出假设。)是的,这正是我将 Int32 与该代码一起使用的结果。
  • 删除类型声明更正了代码。谢谢大家!

标签: haskell


【解决方案1】:

问题在于类型声明primelist :: Int -&gt; [Int]。它强制 Haskell 使用本机整数,即 32 位平台上的 32 位整数。然而,如果你忽略它,Haskell 将推断函数类型为Integer -&gt; [Integer]。整数允许以任意精度进行计算,但比本机类型慢一点。

引用 Haskell 常见问题中的“What's the difference between Integer and Int"”:

对 Int 的操作可能比对 Integer 的操作快得多,但是 上溢和下溢会导致奇怪的错误

这不是事实。

【讨论】:

    【解决方案2】:

    我不确定这是否会对您有所帮助,但我也在通过 Project Euler 来帮助自学 Haskell,我设计了以下解决方案:

    defacto :: Integer -> Integer -> Integer
    defacto x p | x == p = 1
                | x`mod`p==0 = defacto (x`div`p) p
                | otherwise = x
    
    gpf :: Integer -> Integer
    gpf = \x -> prim (x,primes)
    
    prim :: (Integer,[Integer]) -> Integer
    prim (x,(p:ps)) | p > x = 1
                    | (defacto x p) == 1 = p
                    | otherwise = prim((defacto x p),ps)
    
    n :: Integer
    n = 600851475143
    

    这里,defacto 从一个数中去除素数,所以defacto 2 12 返回 4,defacto 5 14 返回 14。gpf 是一个查找最大素数的函数,尽管它需要一个列表以x 为基础,使其在范围内。关键组件是prim,如果数字小于下一个素数,则返回 1,如果 x 是该素数的完美幂(即,如果所有其他小于 p 的素数都已从 x 中分解出来),否则对分解后的 x 和截断的素数列表执行递归调用。这具有在线性遍历素数列表的同时不断缩小 x 的效果,因此我们不需要测试任何不能分解为 x 的素数,并且我们不需要在 x 的缩减值上继续重新测试相同的素数。希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多