让SML NJ中的val声明

时间:2015-12-16 05:39:49

标签: smlnj

我在了解其运作方式上存在精神障碍,并希望能得到一些指导。下面的函数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,如果它击中了其他地方?

1 个答案:

答案 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
-

如您所见,函数flet绑定部分递归调用自身。 (查看代码: 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的第二个和第三个等元素的正确放置。