Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion 如何在SML中将递归函数转换为尾部递归函数?_Recursion_Sml_Tail Recursion - Fatal编程技术网

Recursion 如何在SML中将递归函数转换为尾部递归函数?

Recursion 如何在SML中将递归函数转换为尾部递归函数?,recursion,sml,tail-recursion,Recursion,Sml,Tail Recursion,我试图在SML中编写一个函数,它将返回列表元素的子序列,以及列表其余元素的序列。 所以,我的功能是 fun subseq (left,right,0) = (left,right) | subseq (left,h::t,len) = let val (left,right) = subseq ([],t,len-1) in (h::left,right) end; fun subseqMain (mai

我试图在SML中编写一个函数,它将返回列表元素的子序列,以及列表其余元素的序列。 所以,我的功能是

fun subseq (left,right,0) = (left,right) |
    subseq (left,h::t,len) =
       let
          val (left,right) = subseq ([],t,len-1)
       in
          (h::left,right)
       end;

fun subseqMain (mainList, length) = subseq ([],mainList,length);
我的问题是如何使这个函数更有效,将其转换为尾部递归函数,而不使用@运算符


谢谢你抽出时间

最简单的方法是使用
rev
。基本上,我们的想法是在每次迭代中使用
left
。然后,您的左子序列将以相反的顺序,这就是
rev
的作用。不幸的是,您必须在子序列上进行两次传递,但实际上没有其他方法可以更快地完成。您将获得的性能增益取决于您使用的编译器。SML/NJ执行CPS转换,因此与堆栈分配相反,非尾部调用会产生少量堆分配,因此您需要支付一些GC开销。在整个SML/NJ基础中,您可以看到,他们在一些地方做了类似的事情,例如,
分区的定义是

fun partition pred l = let
      fun loop ([],trueList,falseList) = (rev trueList, rev falseList)
        | loop (h::t,trueList,falseList) = 
            if pred h then loop(t, h::trueList, falseList)
            else loop(t, trueList, h::falseList)
      in loop (l,[],[]) end
您的另一个选择是手动将其转换为Continuation Passing样式(CPS),基本上将“剩余的计算”封装在一个函数中,我们称之为Continuation。当函数完成时,它只是将其结果传递给传入的延续。完整地解释CPS可能超出了这个答案的范围,所以我建议做一些谷歌搜索来真正掌握它。
分区
示例可能如下所示:

fun partition pred l = let
    fun loop([], k) = k([], [])
       |loop(h::t, k) = loop(t, fn (tr, fl) => if pred h then k(h::tr, fl) else k(tr, h::fl))
    in loop(l, fn res => res) end
也就是说,如果您不打算转换为尾部递归,那么有一种更直接的方法来实现您所拥有的:

fun subseq(l, 0) = ([], l)
   |subseq(h::t, i) = 
      let val (l, r) = subseq(t, i-1)
      in (h::l, r) end
   |subseq([], i) = raise Subscript
通过,用任何语言。