解释这段输出素数流的haskell代码

问题描述 投票:19回答:5

我在理解这段代码时遇到麻烦:

let
  sieve (p:xs) = p : sieve (filter (\ x -> x `mod` p /= 0) xs)
in sieve [2 .. ]

有人可以为我分解吗?我知道其中存在递归,但这就是我无法理解此示例中的递归如何工作的问题。

haskell primes lazy-evaluation
5个回答
14
投票

实际上非常优雅。

首先,我们定义一个函数sieve,它接受元素列表:

sieve (p:xs) =

sieve的主体中,我们采用列表的开头(因为我们要传递无限列表[2..],并且2被定义为素数),并将其(懒惰!)附加到应用结果上sieve到列表的其余部分:

p : sieve (filter (\ x -> x 'mod' p /= 0) xs)

因此,让我们看一下在其余列表上起作用的代码:

sieve (filter (\ x -> x 'mod' p /= 0) xs)

我们正在将sieve应用于过滤列表。让我们分解一下过滤器部分的功能:

filter (\ x -> x 'mod' p /= 0) xs

filter接受一个函数和一个应用该函数的列表,并保留满足该函数给定条件的元素。在这种情况下,filter具有匿名功能:

\ x -> x 'mod' p /= 0

此匿名函数采用一个参数x。它检查xmodulusp(每次调用sieve时,列表的开头):

 x 'mod' p

如果模量不等于0:

 x 'mod' p /= 0

然后元素x保留在列表中。如果等于0,则将其过滤掉。这是有道理的:如果x可被p整除,则x不仅可被1及其本身整除,因此不是素数。


22
投票

与其他人在这里所说的相反,此函数does not实现了真正的sieve of Eratosthenes。它确实以类似的方式返回质数的初始序列,因此可以将其视为Eratosthenes的筛子。

当mipadi posted回答时,我即将解释代码;我可以删除它,但是由于我花了一些时间,并且由于我们的答案并不完全相同,因此将其保留在此处。


总而言之,请注意,您发布的代码中存在一些语法错误。正确的代码是,

let sieve (p:xs) = p : sieve (filter (\x -> x `mod` p /= 0) xs) in sieve [2..]
  1. let x in y定义x,并允许在y中使用其定义。该表达式的结果是y的结果。因此,在这种情况下,我们定义一个函数sieve,并将将[2..]应用于sieve的结果返回。

  2. 现在让我们仔细看一下该表达式的let部分:

    sieve (p:xs) = p : sieve (filter (\x -> x `mod` p /= 0) xs)
    
    1. 这定义了一个函数sieve,该函数将列表作为第一个参数。
    2. (p:xs)是一个pattern,它使p与列表的头部匹配,xs与尾部(除了头部)匹配。
    3. [通常,p : xs是其第一个元素为p的列表。 xs是包含剩余元素的列表。因此,sieve返回它接收到的列表的第一个元素。
    4. 不查看列表的其余部分:

      sieve (filter (\x -> x `mod` p /= 0) xs)
      
      1. 我们可以看到sieve被递归调用。因此,filter表达式将返回一个列表。
      2. filter具有过滤器功能和一个列表。它仅返回列表中过滤功能对其返回true的那些元素。
      3. 在这种情况下,filter是要过滤的列表,

        xs

        是过滤器功能。

      4. 过滤器函数接受单个参数(\x -> x `mod` p /= 0) ,如果不是x的倍数,则返回true。
  3. 现在定义了p,我们将其传递给sieve,即从2开始的所有自然数的列表。因此,

    1. 将返回数字2。所有其他自然数(是2的倍数)将被丢弃。
    2. 因此,第二个数字为3。它将被返回。其他所有3的倍数将被丢弃。
    3. 因此,下一个数字将为5等。>

9
投票

它定义了一个生成器-一个称为“筛子”的流变流器


1
投票

它说:“某些列表的筛子是列表的第一个元素(我们将其称为p),其余列表的筛子经过过滤,从而仅允许被p不可除的元素通过”。然后,它通过将所有整数从2返回到无穷大(即2,然后是所有不能被2整除的整数,等等)的筛子来开始事情。

在攻击Haskell之前,我建议Sieve of Eratosthenes。>>


1
投票

它说“一些列表的筛子是列表的第一个元素(我们称之为p)和列表其余部分的筛子,过滤使得只有不能被p整除的元素才能通过”。然后通过将所有整数的筛子从2返回到无穷大(这是2然后是所有整数的筛子,不能被2整除等)来开始。

在你攻击Haskell之前我推荐The Little Schemer

© www.soinside.com 2019 - 2024. All rights reserved.