CPS归并排序导致栈溢出
CPS merge sort causes a stack overflow
由于非尾递归导致堆栈溢出问题,我使用延续来使大列表的排序变得可行。
我是这样实现排序的(你可以在这里看到完整的代码:http://paste.ubuntu.com/13481004/)
let merge_sort l =
let rec merge_sort' l cont =
match l with
| [] -> cont []
| [x] -> cont [x]
| _ ->
let (a,b) = split l
in
merge_sort' a
(fun leftRes -> merge_sort' b
(* OVERFLOW HERE *) (fun rightRes -> cont (merge leftRes rightRes) )
)
in merge_sort' l (fun x -> x)
尽管如此,我还是在指示的行中遇到了堆栈溢出。
我做错了什么?
OCaml 标准库的 (@)
不是 尾递归。 merge
代码中的函数 http://paste.ubuntu.com/13481004/ 使用了 (@)
,这就是堆栈溢出的原因。
list.mli
说:
val append : 'a list -> 'a list -> 'a list
(** Catenate two lists. Same function as the infix operator [@].
Not tail-recursive (length of the first argument). The [@]
operator is not tail-recursive either. *)
但不幸的是,这个事实并没有写在 pervasives.mli
中,其中真正声明 (@)
:
val ( @ ) : 'a list -> 'a list -> 'a list
(** List concatenation. *)
这不好 :-( 我已经在 OCaml 开发页面上提出了一个问题。
我将 (@)
重新定义为 fun x y -> rev_append (rev x) y
然后您的代码运行 w/o 堆栈溢出。更优雅的是,您可以将 (rev a) @ l
之类的代码替换为 rev_append a l
.
P.S。 pervasives.mli
中的 (@)
将在下一版本的 OCaml 中注释为 "not tail recursive"。
由于非尾递归导致堆栈溢出问题,我使用延续来使大列表的排序变得可行。
我是这样实现排序的(你可以在这里看到完整的代码:http://paste.ubuntu.com/13481004/)
let merge_sort l =
let rec merge_sort' l cont =
match l with
| [] -> cont []
| [x] -> cont [x]
| _ ->
let (a,b) = split l
in
merge_sort' a
(fun leftRes -> merge_sort' b
(* OVERFLOW HERE *) (fun rightRes -> cont (merge leftRes rightRes) )
)
in merge_sort' l (fun x -> x)
尽管如此,我还是在指示的行中遇到了堆栈溢出。 我做错了什么?
(@)
不是 尾递归。 merge
代码中的函数 http://paste.ubuntu.com/13481004/ 使用了 (@)
,这就是堆栈溢出的原因。
list.mli
说:
val append : 'a list -> 'a list -> 'a list
(** Catenate two lists. Same function as the infix operator [@].
Not tail-recursive (length of the first argument). The [@]
operator is not tail-recursive either. *)
但不幸的是,这个事实并没有写在 pervasives.mli
中,其中真正声明 (@)
:
val ( @ ) : 'a list -> 'a list -> 'a list
(** List concatenation. *)
这不好 :-( 我已经在 OCaml 开发页面上提出了一个问题。
我将 (@)
重新定义为 fun x y -> rev_append (rev x) y
然后您的代码运行 w/o 堆栈溢出。更优雅的是,您可以将 (rev a) @ l
之类的代码替换为 rev_append a l
.
P.S。 pervasives.mli
中的 (@)
将在下一版本的 OCaml 中注释为 "not tail recursive"。