Ocaml 在不破坏堆栈的情况下生成素数
我正在学习OCaml(所以请原谅我的风格),并试图编写一个函数,生成一个素数列表,其上限为。我已经用几种不同的方法做到了这一点,所有这些方法都有效,直到你将它们扩展到一个相对较高的上限 如何更改这些(任意一个)以使递归不会填满堆栈?我以为我的while循环版本可以实现这一点,但显然不行 发电机 Eratosthenes v2的递归筛Ocaml 在不破坏堆栈的情况下生成素数,ocaml,primes,Ocaml,Primes,我正在学习OCaml(所以请原谅我的风格),并试图编写一个函数,生成一个素数列表,其上限为。我已经用几种不同的方法做到了这一点,所有这些方法都有效,直到你将它们扩展到一个相对较高的上限 如何更改这些(任意一个)以使递归不会填满堆栈?我以为我的while循环版本可以实现这一点,但显然不行 发电机 Eratosthenes v2的递归筛 设素数max= 让我们来测试一下= 设h=List.hd toTest 和t=List.tl toTest in 让我们把x=(x模h 0)分为 让非分隔符=Lis
设素数max=
让我们来测试一下=
设h=List.hd toTest
和t=List.tl toTest in
让我们把x=(x模h 0)分为
让非分隔符=List.filter不在
如果非分频器=[],则[h]
中的else(h::筛选非分隔符)
让rec范围为a到b=
如果a>b,则[]
否则a::范围(a+1)b in
设p=最大范围2英寸
p筛;;
而埃拉托斯烯的环筛
设素数max=
让rec范围为a到b=
如果a>b,则[]
否则a::范围(a+1)b in
让尾=参考(最大范围2)
和p=ref[]in
虽然尾
让h=List.hd!尾
t=List.tl!尾随
让我们把x=(x模h 0)分为
将newTail=ref(List.filter不提供t)放入
尾巴:=!纽泰尔;
p:=h:!P
完成;
!P
堆栈溢出是因为范围函数不是尾部递归函数。一个有效的方法是,例如
let rec range store a b =
if a > b then store
else range (a :: store) (a + 1) b
in
let p = List.rev (range [] 2 max) in
使用该定义和格式行,可以
$ ocamlopt -o primes2 primes2.ml
$ ./primes2
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
...
既然你在学习,我也会给你一些不请自来的风格评论:)
- 不要使用hd和tl。更喜欢模式匹配。然后编译器可以告诉你你错过的案例。例如 让rec筛子进行测试= 设h=List.hd toTest 和t=List.tl toTest in
let rec sieve found = function
| h :: t -> ...
| [] -> Error handling...
- 不要使用x=[]。使用图案修补 将x与 | [] -> ... |h::t->
- 使用匿名函数,而不是在
- 谨慎使用命令式功能
- 你声称是埃拉托斯坦筛的算法实际上不是;他们使用试除法而不是筛选法,通过寻找余数(mod运算符)与零的比较,很容易发现这一点。下面是Eratosthenes筛的一个简单实现,使用伪代码而不是Ocaml,因为我已经很久没有编写Ocaml代码了:
function primes(n)
sieve := makeArray(2..n, True)
for p from 2 to n
if sieve[p]
output p
for i from p*p to n step p
sieve[i] := False
这可以进一步优化,尽管对于n=2000000这样的小限制,这样做没有什么意义;在任何情况下,筛子将比您正在使用的试用版快得多。如果您对使用素数编程感兴趣,我在我的博客上谦虚地推荐这一点。对于您使用匿名函数的建议,我完全不同意
List.exists hasDivisor p
是清除的,List.filter不提供t
。具有匿名函数的版本不可用。名称是文档。x*x+y*y
中的子表达式x*x
不应该有名字,但是(funx->(xmodh0))
应该有(快速:它的意图是什么?)我将强调简短。这个特定函数体的意图与英文文本一样容易确定,并且不需要再添加一个需要记住的名称(尽管只需要一行代码)。
let rec range store a b =
if a > b then store
else range (a :: store) (a + 1) b
in
let p = List.rev (range [] 2 max) in
$ ocamlopt -o primes2 primes2.ml
$ ./primes2
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
...
let rec sieve found = function
| h :: t -> ...
| [] -> Error handling...
function primes(n)
sieve := makeArray(2..n, True)
for p from 2 to n
if sieve[p]
output p
for i from p*p to n step p
sieve[i] := False