SML-从列表中获取特定元素而不使用List.nth

时间:2018-10-03 01:22:15

标签: sml

我试图学习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);

2 个答案:

答案 0 :(得分:1)

正如约翰建议的那样,索引一个空列表可能会引发异常,而不是返回0。这使得nth适用于任何类型的列表,而不仅仅是int list的子集,对于这些子集,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具有第i个元素{{1} },则返回x,否则返回SOME x

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)来解决第三个函数主体的...中的问题,但这将在每个递归步骤上执行,即使您很可能只需要检查一次即可

此函数的健壮版本在将其传递给负索引时会引发错误。否则,由于递归情况(第3个情况)不会收敛到两个基本情况(情况1和2),因此函数可能会导致负循环,直到内存用尽。对于基于异常的版本,您可以编写:

if n < 0 then ...

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

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

答案 1 :(得分:0)

一种简单的方法:

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))