【问题标题】:Haskell is evaluating much faster then I thought it would (no complaints)Haskell 的评估速度比我想象的要快得多(没有抱怨)
【发布时间】:2014-08-07 10:53:44
【问题描述】:

我写了以下代码来检查一个数字是否是素数:

factorsOf :: Int -> [Int]
factorsOf n = [factor | factor <- [2..sqrtOfN], n `rem` factor == 0]
    where sqrtOfN = round . sqrt $ fromIntegral $ n+1

isPrime :: Int -> Bool
isPrime n
    | factorsOf n == [] = True
    | otherwise = False

它有效,但我注意到一些奇怪的东西。如果我对一个大数(比如 100000001)运行 factorOf,则需要几秒钟来计算所有因素。如果我在同一个数字上运行 isPrime,如果它找到一个因素,它几乎会立即返回。 Haskell 是否真的跟踪函数将返回以支持(我假设)惰性求值的条件?如果是真的,那就太棒了。

【问题讨论】:

  • isPrime 中的守卫只对factorsOf 是否包含任何元素感兴趣。只要找到一个因素,就可以确定isPrime的结果。无需评估整个因素列表。
  • 尝试将性能与较大的素数(例如 1000000007)作为输入进行比较。
  • @Xeo 这就是我的想法;这很酷。如果我想了解更多这方面的信息,是否有任何关于惰性评估的文章,或者守卫是一个特例?
  • @Niklas B. 我假设它需要的时间与 factorOf 通话时间一样长?
  • factorsOf 100000001[17],它会立即计算。好吧,如果您在烤面包机上运行,​​那么也许,但在现代台式计算机上,没有 32 位数字对于这个计算来说是“大”的。想要大量因素吗?尝试factorsOf $ product [1..17],但将Int 替换为Integer 以获得任意精度的算术。对于非常非常的大型列表,请尝试product [1..20]

标签: haskell lazy-evaluation


【解决方案1】:

正如 cmets 中所指出的,isPrime 只需对factorsOf 的结果进行足够深的评估,以确定它是否为空列表。你可以像这样更惯用地写isPrime

isPrime = null . factorsOf

null 是简单的

null (_:_) = False
null _ = True

请注意,只要 null 可以在 (:) 构造函数上进行模式匹配,它就会返回结果而不评估列表的其余部分。

这意味着只有factorsOf 只需要计算isPrime 返回的第一个因子,而factorsOf 本身将计算整个列表。

【讨论】:

    【解决方案2】:

    懒惰的基本原则是,除非真的需要,否则不会评估任何内容。在您的情况下真正需要意味着第一个函数必须返回,以便另一个函数获取其输入。你可以阅读更多关于 Haskell 的懒惰here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多