我试图学习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 :(得分: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))