我正在寻找Haskell中以下selection sort代码的非尾递归版本:
import Data.List (minimum, delete)
ssort :: Ord t => [t] -> [t]
ssort [] = []
ssort xs = let { x = minimum xs } in x : ssort (delete x xs)
能否请您提供选择排序的非尾递归版本?
我知道更改原始代码不是一个好主意,但是我需要该版本才能进行实验。
答案 0 :(得分:5)
简短答案:代码不是递归的。
能否请您提供选择排序的非尾递归版本?
代码不是不是尾递归。它是"tail recursive modulo cons" [wiki],但不是尾递归。
Haskell wiki显示了如何确定函数是否为尾递归:
这是“尾递归”的正式定义。 “
f
发生在t
中” 表示f
是t
的自由变量。将函数定义为(在let或顶层)时:
f = t
其中
f
是名称,t
是lambda项,f
是尾递归 如果f
在t
中以递归方式出现在尾部。f
递归出现在t
仅当f
出现在t
中且具有以下任一条件时:
t
是可变的;t
为\var -> t0
,并且f在t0
中以递归方式出现在尾部;t
为t0 t1
,并且f在t0
中以递归方式出现在尾部,而在t1
中则不出现;t
为let bs in t0
,并且f
在t0
中以递归方式出现在尾部,并且对于var = t1
中的每个活页夹bs
,f
在t1
中不会发生;t
为case t0 of bs
,f
中没有t0
,b
中的每个分支bs
,f
才不是 在b
中出现或以递归方式出现在尾部;
- 当我们说“发生在
b
”,b
的格式为D vars -> t1
(其中D
是一些数据构造函数,vars
是一系列名称),我们正在考虑 拉姆达抽象\vars -> t1
而非b
。
表达式t
是\xs -> let x = minimum xs in x : ssort (delete x xs)
,所以我们可以在这里取第二项,但是ssort
必须在let ... in ...
语句中为尾递归,这是第四种情况。
但是第四种情况要求ssort
在let ... in ...
表达式的“ body”中是尾递归的。此表达式为((:) x) (ssort delete xs)
。因此,这是第三种情况。
在第三种情况下,表达式的形状为t0 t1
,此处为t0 = (:) x
和t1 = ssort delete xs
。由于ssort
中没有出现t0
,因此这里没有尾递归。
答案 1 :(得分:3)
由于您调用:
cons函数,因此显示的代码不是尾部递归的。所有递归调用将保留在内存堆栈上,等待对ssort (delete x xs)
的求值完成。尾递归版本可能如下所示:
import Data.List (minimum, delete)
ssort :: Ord t => [t] -> [t] -> [t]
ssort [] acc = reverse acc
ssort xs acc = let { x = minimum xs } in ssort (delete x xs) (x : acc)