【问题标题】:Is this even a function in Haskell ? If so, how should we read it?这甚至是 Haskell 中的一个函数吗?如果是这样,我们应该如何阅读它?
【发布时间】:2018-08-02 15:16:55
【问题描述】:

在 Doets 等人的 The Haskell Road to Logic, Math and Programming 一书中,在第 103 页,给出了

prime :: Integer -> Bool
prime n | n < 1     = error "not a positive integer"
        | n == 1    = False
        | otherwise = ldp n == n where 
  ldp    = ldpf primes
  ldpf (p:ps) m | rem m p == 0 = p
                | p^2 > m = m
                | otherwise = ldpf ps m 
  primes = 2 : filter prime [3..]

但是,这个函数的逻辑不是循环的吗?我的意思是我认为我对递归函数很满意,但我不认为这是一个递归函数。即使是这样,我也无法理解它的逻辑,所以我的问题是如何阅读这样一个函数的逻辑。

编辑:

我困惑的原因是prime函数使用了列表primes,但是要生成那个列表,我们也使用了函数prime,所以看起来有一个循环逻辑,或者我只是不理解带有惰性求值的递归函数。

【问题讨论】:

  • 请将代码发布为文本而不是屏幕截图。它使阅读、本地测试和搜索变得更加容易。
  • 哪部分让你觉得逻辑是循环的
  • @Carl 查看我的编辑。
  • Haskell 是懒惰的;跟踪对prime 2 的调用,并注意您在对ldpf 的调用中从未实际使用过ps。这意味着对prime 的递归调用在您真正需要之前不会真正进行。
  • Haskell 就是这么神奇。这是一个太复杂的函数,无法考虑,请先尝试了解这个斐波那契数列实现:fibs = 0 : 1 : zipWith (+) fibs (tail fibs)。请注意,它会生成一个 infinite 列表。

标签: haskell recursion primes lazy-evaluation


【解决方案1】:

ldp n == n 条件可以等效地重写为

ldpf primes n == n
=
null [() | p <- takeWhile (\p -> p^2 <= n) primes, rem n p==0]
=
and [rem n p > 0 | p <- takeWhile (\p -> p^2 <= n) primes]

所以对于任何给定的n,调用prime n = ldp n == n只需要生成列表

primes = 2 : 过滤素数 [3..]
       = 2 : 过滤器 (\n -> ldpf primes n == n) [3..]
       = 2 : 过滤器 (\n -> 和 [rem n p > 0
                                | p  p^2 素数])
                          [3..]

直到最小的素数q &gt; floor (sqrt $ fromIntegral n),为此只需要不大于q平方根的素数。而要生成这些,只需要不大于 that 平方根的数字。很快我们就完全不需要任何素数了,例如

prime 3
= 
ldpf primes 3 == 3
=
and [rem 3 p > 0 | p <- takeWhile (\p -> p^2 <= 3) (2 : filter prime [3..])]
= 
and [rem 3 p > 0 | p <- takeWhile (<= 3) (4 : 
                                      map (\p -> p^2) (filter prime [3..]))]
= 
and [rem 3 p > 0 | p <- []]
=
and []
=
True

因为2 已经使谓词失败:(2^2 &lt;= 3) = (4 &lt;= 3) = False

在测试4 时,primes 将被探测是否包含数字3,但这没关系,正如我们刚刚在上面看到的那样:

prime 4
=
and [rem 4 p > 0 | p <- takeWhile (\p -> p^2 <= 4) primes]
= 
and [rem 4 p > 0 | p <- takeWhile (<= 4) (4 : 
                               map (\p -> p^2) (filter prime [3..]))]
= 
and [rem 4 p > 0 | p <- 4 : takeWhile (<= 4) (9 :
                               map (\p -> p^2) (filter prime [4..]))]
= 
and [rem 4 p > 0 | p <- 4 : []]
=
False

然后我们可以在 GHCi 提示符下检查它,

> :sprint primes
2 : 3 : _

(要使上述方法正常工作,您需要将 primesprime 函数中取出并使其本身成为顶级实体)。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2011-10-04
  • 2022-10-14
  • 1970-01-01
  • 2014-12-08
  • 2019-03-04
  • 2020-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多