所以我刚进入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)];
我会上传一张带有错误的图片,以便有人可以向我解释口译员试图对我说的话。
" a"旁边的数字只显示列表中这些元素的顺序。对于L = [1,2,3,4,5],对于i = 2,期望结果是List L = [3,4,5,1,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ţ已经对语法问题给出了足够的答案;以下是一些进一步的建议:
使用模式匹配而不是hd
和tl
。
考虑基本情况;你能想到的最简单的子问题是什么?例如。循环空列表将始终给出空列表而不管 n ,并且循环 L 0次将始终返回 L 。将两个基本案例都作为模式有所帮助。
考虑递归情况;顶部元素(假设它存在)循环, i 减1,直到最终 i 为0或 L 为空。因为第二个基本案例捕获了空列表,我们可以自由地假设 L 在这里是非空的,在这种情况下它将匹配模式x::xs
。
fun cycle 0 xs = xs
| cycle i [] = []
| cycle i (x::xs) = cycle (i-1) (xs @ [x])
根据0 <= i
和i <= 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
主要操作,即xs @ [x]
非常低效,因为它的运行时间与xs
的长度成正比,并且被激活 n 次。因此当{em> O(min(n,| L |))之类的东西应该可以实现时,cycle
的运行时间变为 O(n•| L |)
如果将循环元素存储在单独的列表中,而不使用@
,则可以制作更快的版本,并在循环元素后将剩余元素与此列表合并。根据您对0 <= i
和i <= length xs
的看法,您可能会遇到以下测试用例的问题:
val cycle_test_1 = (cycle 5 [1,2,3,4] = [2,3,4,1])