标准ML递归函数错误

时间:2016-03-23 22:19:36

标签: sml

所以我刚进入ML编程,我在一本书中找到了这个练习。该练习说要构建一个带整数和列表的递归函数。如果L = [a1,a2,a3],则期望的结果是[ai + 1,ai + 2,...,an,a1,a2,...,ai]。所以我写了一个函数,经过很长时间后,我把错误缩小到了一个我无法理解的错误。这是我的功能:

fun cycle L i = 
    if i = 0 then L
    else (cycle tl(L) (i-1)) @ [hd(L)];

我会上传一张带有错误的图片,以便有人可以向我解释口译员试图对我说的话。

enter image description here

" a"旁边的数字只显示列表中这些元素的顺序。对于L = [1,2,3,4,5],对于i = 2,期望结果是List L = [3,4,5,1,2 ]。我不认为列表的类型在这个问题上是必不可少的。希望这个进一步的解释有所帮助

2 个答案:

答案 0 :(得分:3)

这是递归调用cycle tl(L) (i-1)的语法问题。

在SML中,函数应用程序的语法是并置,而不是括号。在您的情况下,tl(L)确实使用参数tl调用函数L,但这仅相当于tl L。括号是多余的,因此被忽略。

现在,如果您更换原始通话中的最小版本,您将获得此结果:cycle tl L (i-1)。它用三个参数调用cycle,而不只是两个。

正确的写作方式是:cycle (tl L) (i-1)

答案 1 :(得分:2)

Ionuţ已经对语法问题给出了足够的答案;以下是一些进一步的建议:

  1. 使用模式匹配而不是hdtl

  2. 考虑基本情况;你能想到的最简单的子问题是什么?例如。循环空列表将始终给出空列表而不管 n ,并且循环 L 0次将始终返回 L 。将两个基本案例都作为模式有所帮助。

  3. 考虑递归情况;顶部元素(假设它存在)循环, i 减1,直到最终 i 为0或 L 为空。因为第二个基本案例捕获了空列表,我们可以自由地假设 L 在这里是非空的,在这种情况下它将匹配模式x::xs

    fun cycle 0 xs = xs
      | cycle i [] = []
      | cycle i (x::xs) = cycle (i-1) (xs @ [x])
    
  4. 根据0 <= ii <= length xs是否是函数的先决条件,您可能希望在激活主递归之前处理这些,例如:通过包装上面的函数:

    fun cycle i ys =
        let fun fun cycle' 0 xs = xs
                  | cycle' i [] = []
                  | cycle' i (x::xs) = cycle' (i-1) (xs @ [x])
        in
          if 0 <= i andalso i <= length xs
          then cycle' i ys
          else raise Domain
        end
    
  5. 主要操作,即xs @ [x]非常低效,因为它的运行时间与xs的长度成正比,并且被激活 n 次。因此当{em> O(min(n,| L |))之类的东西应该可以实现时,cycle的运行时间变为 O(n•| L |)

    如果将循环元素存储在单独的列表中,而不使用@,则可以制作更快的版本,并在循环元素后将剩余元素与此列表合并。根据您对0 <= ii <= length xs的看法,您可能会遇到以下测试用例的问题:

    val cycle_test_1 = (cycle 5 [1,2,3,4] = [2,3,4,1])