我在了解其运作方式上存在精神障碍,并希望能得到一些指导。下面的函数f将对整数列表进行排序(f [1,2,3])。我坚持的部分是val声明和递归中发生的事情。我知道val声明允许我将列表中的第二个值与第一个值进行比较,但是我对列表连接感到困惑。似乎函数只是比较前两个值然后在列表的其余部分(即x :: y :: ys)。我不确定f ls实际上是如何工作的。那是......
1)比较前两个值并将其添加到列表
2)然后递归调用f ls?
似乎就是这种情况,但后来我对'" ys" - 看起来每个电话都会加上列表的结尾。我知道排序有效,但不确定它是如何工作的。
fun f ([x]) = [x]
| f(x :: ls) =
let
val (y :: ys) = f ls
in
if y > x then x :: y :: ys
else
y :: x :: ys
end
编辑 - 更多地考虑这个问题,是因为in / end正文中的y::ys
实际上是递归调用的吗?如果是这样,SML足够聪明,知道它应该在x::ys
地方使用y::ys
,如果它击中了其他地方?
答案 0 :(得分:4)
首先,当列表非常随机时,排序不起作用,例如f [2,3,4,1,2,4,6,0,6,7]
其次,回答关于这个特定功能如何工作的问题,
您可以通过对代码添加print
来轻松地对其进行可视化:
fun f ([x]) = [x]
| f(x :: ls) = (print( (Int.toString (x)) ^ "\n");
let
val (y :: ys) = f ls
val x_str = Int.toString (x)
val y_str = Int.toString (y)
val ys_str = concat (map Int.toString ys);
val y_gt_x = if y > x then " ---> this one applies " else ""
val x_gt_y = if x >= y then " ---> this one applies " else ""
in
(print ("if " ^ y_str ^ " > " ^ x_str ^
"\n then " ^ x_str ^ " :: " ^ y_str ^ ys_str ^ y_gt_x ^
"\n else " ^ y_str ^ " :: " ^ x_str ^ ys_str ^ x_gt_y ^ "\n");
if y > x then x :: y :: ys
else
y :: x :: ys)
end)
对于上面的随机列表输出以下内容:
- f [2,3,4,1,2,4,6,0,6,7];
2
3
4
1
2
4
6
0
6
if 7 > 6
then 6 :: 7 ---> this one applies
else 7 :: 6
if 6 > 0
then 0 :: 67 ---> this one applies
else 6 :: 07
if 0 > 6
then 6 :: 067
else 0 :: 667 ---> this one applies
if 0 > 4
then 4 :: 0667
else 0 :: 4667 ---> this one applies
if 0 > 2
then 2 :: 04667
else 0 :: 24667 ---> this one applies
if 0 > 1
then 1 :: 024667
else 0 :: 124667 ---> this one applies
if 0 > 4
then 4 :: 0124667
else 0 :: 4124667 ---> this one applies
if 0 > 3
then 3 :: 04124667
else 0 :: 34124667 ---> this one applies
if 0 > 2
then 2 :: 034124667
else 0 :: 234124667 ---> this one applies
val it = [0,2,3,4,1,2,4,6,6,7] : int list
-
如您所见,函数f
以let
绑定部分递归调用自身。 (查看代码:
let
val (y :: ys) = f ls
如您所见,f ls
是函数f
的递归调用,因此您对y :: ys
正文中递归调用的in
分析不正确这只是将元素y
添加到列表ys
)
除了列表末尾的所有方式外,in
主体不会被评估。因此,in
正文将首先评估列表的最后两个元素,例如7 > 6
并相应地增加列表ys
。
第三,回答关于为什么排序函数f
不能正常工作的第一点是因为它不断向ys
添加新元素而不查看新元素是否按顺序放置在ys
中关于其余元素。是的,列表ys
的第一个元素与要预先添加的新元素进行比较,因此两个中的最大元素将首先加到ys
的其余部分,但这并不能保证关于ys
的第二个和第三个等元素的正确放置。