【问题标题】:SML - Get specific Element out of List without using List.nthSML - 在不使用 List.nth 的情况下从列表中获取特定元素
【发布时间】:2018-10-03 01:22:15
【问题描述】:

我正在尝试学习 SML atm 的基础知识,但偶然发现了一项我找不到答案的任务。

编写一个函数,接收一个 int 和一个列表,返回列表中给定 int 索引上的特定元素。如您所见,它与 List.nth() 函数完全一样。

现在我很好奇。这就是我走了多远,但我想不出一种手动定位特定索引的方法。

fun nth(nil, _)     = 0
  | nth(x::xs, 0)   = x;
  | nth(x::xs, y)   = 

val list = [1, 2, 3];
nth(list, 0);

【问题讨论】:

  • 您的第一个基本案例似乎有问题。不应该留下未定义或触发异常而不是返回数字 0 吗?至于其余部分,这里有一个提示:请注意,例如x::xs 的第 7 个元素与 xs 的第 6 个元素相同。
  • 谢谢你的回答,我对最后的提示已经有了新的认识。我的问题是,即使我知道元素的索引,我也不知道如何单独与它们交互。
  • 在这种幼稚的递归方法中显式地与索引交互(除了从它们中减去 1)。您只需倒计时(通过递归调用)直到索引达到 0,此时您返回剩余列表的头部。
  • 非常感谢,我还是不太习惯SML的功能。我搜索的简单解决方案是:nth(xs, y-1)

标签: sml


【解决方案1】:

正如 John 所建议的,索引空列表可能会引发异常而不是返回 0。这使得 nth 适用于任何类型的列表,而不仅仅是 int lists 的子集,其中 0 可以合理地被认为是“不结果”。似乎该函数缺少递归,无法用于超过 0 的任何索引。这是一个可以使用的模板:

fun nth ([], _) = raise Empty
  | nth (x::_, 0) = x
  | nth (_::xs, n) = ...

这里添加了一个例外,并且在函数的每种情况下都不会使用的变量已被伪变量_ 屏蔽掉。您可能还需要更多信息的错误消息。

fun nth ([], n) = raise Fail "Failed to find the appropriate index!"
  | nth (x::_, 0) = x
  | nth (_::xs, n) = ...

nth 的“更安全”版本具有 'a list * int -> 'a option 类型,即对于 nth (xs, i),如果 xs 具有 ith 元素 x,则返回 SOME x,如果没有't,它返回NONE

fun nth_safe ([], _) = NONE
  | nth_safe (x::_, 0) = SOME x
  | nth_safe (_::xs, n) = ...

它“更安全”,因为如果列表不够长,它不会抛出异常。对抗性示例:nth ([0,1,2], 3)

但如果索引为负数,它仍然无法处理。对抗性示例:nth ([0,1,2], ~1)

您可以使用 if n < 0 then ... 在第三个函数体的 ... 中解决该问题,但随后会在每个递归步骤中执行,即使您很可能只需要检查一次。

当您向它传递负索引时,此函数的健壮版本会引发错误。否则,您的函数可能会导致您进行负循环,直到内存不足,因为递归情况(第三种情况)不会收敛到两种基本情况(情况 1 和 2)。对于基于异常的版本,可以这样写:

exception IndexError of int
fun nth (xs, n) =
    let fun go ([], _) = raise IndexError n
          | go (x::_, 0) = x
          | go (_::ys, i) = ...
    in if n < 0 then raise IndexError n else go (xs, n)
    end

使用错误感知数据类型的健壮版本可能看起来像:

fun nth (xs, n) =
    let fun go ([], _) = NONE
          | go (x::_, 0) = SOME x
          | go (_::ys, i) = ...
    in if n < 0 then NONE else go (xs, n)
    end

一个健壮的版本使用错误感知数据类型来捕获索引错误,就像带有自定义 IndexError 异常的基于异常的版本一样:

datatype ('a, 'b) either = Left of 'a | Right of 'b
fun nth (xs, n) =
    let fun go ([], _) = Left n
          | go (x::_, 0) = Right x
          | go (_::ys, i) = ...
    in if n < 0 then Left n else go (xs, n)
    end

val example_1 = nth ([2,3,5], 5)  (* gives: Left 5  *)
val example_2 = nth ([2,3,5], ~1) (* gives: Left ~1 *)
val example_3 = nth ([2,3,5], 2)  (* gives: Right 5 *)

【讨论】:

    【解决方案2】:

    一个简单的方法:

    fun nth (nil,0) = raise Fail "You are out of bounds with nth element"
      | nth ((x::xr),n) = if n=0 then x else nth (xr,(n-1))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-07
      • 2014-12-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多