SML:获取列表中项的索引

3

我刚接触SML,尝试获取列表中某个项的索引。我知道使用List.nth将给我一个索引位置处的项目值,但我想要的是索引值。可能有我不知道的内置函数。在我的情况下,该列表不包含重复项,因此如果该项在列表中,我会得到索引,否则它返回~1。这是我目前的代码。它能工作,但我认为它不够简洁:

val L=[1,2,3,4,5];
val m=length L-1;
fun Index(item, m, L)=if m<0 then ~1 else
    if List.nth(L, m)=item then m else Index(item,m-1,L);

1
你的问题是什么?我认为至少在List结构中没有明确执行此操作的标准函数。至于清理代码,我建议:1)使用Option或异常代替返回“~1”,2)通过将函数包装在外部函数中来隐藏参数“m”,3)对“m”进行模式匹配以消除一个条件(“if m < 0 ...”)。 - waldrumpus
感谢这些提示。问题实际上是:“做这件事情的最佳方式是什么?”既然m的值依赖于L的长度,所以不将m传递给函数可能会更好,但像我所说,我刚接触SML,不确定如何将它们组合起来。代码的原因是:我有两个不同类型但相关的列表。在列表一中更新一个项目需要在列表二中的相同位置更新一个项目。我相信List结构可以通过“zip”提供类似的功能,但现在这种方法可行。 - One Freak
3个回答

5

为了阐述我之前的评论,我建议对实现进行一些更改,以更好地适应ML习惯用语:

fun index(item, xs) =
  let
    fun index'(m, nil) = NONE
      | index'(m, x::xr) = if x = item then SOME m else index'(m + 1, xr)
  in
    index'(0, xs)
  end

以下是改动的内容:

  • index现在返回int option类型的值。其中NONE表示元素不在列表中,SOME i表示元素在列表中,并且其第一次出现的索引为i。这样就避免了使用特殊值(~1),同时函数的用途可以从其类型推断出来。
  • 通过将函数重命名为index'并将其封装到外部函数index中,并使用适当的参数调用它,隐藏参数m。通常情况下,带有下划线的字符(`)表示辅助变量。
  • 对列表进行模式匹配以获取单个元素,从而消除了使用List.nth的需要。

此外,请注意,大多数情况下,函数和变量名以小写字母开头(如index而非Index),而大写字母用于构造函数常量(如SOME)等。


感谢您的详细解释。我在 Stack Overflow 上看到过这个习惯用语好几次,但一直不明白为什么要给内部和外部函数都取同样的名字。我试着在谷歌上搜索,但很难搜索出你不知道叫什么的东西。再次感谢! :) - Annie Lagang

0

我想提出一个更简单、效率较低的版本的index函数。我同意使用异常而不是int option并且它不是尾递归的做法并不理想。但是这个版本肯定更易于阅读,因此可以作为学习材料:

fun index (x, []) = raise Subscript
  | index (x, y::ys) =
    if x = y then 0 else 1 + index (x, ys)

-1
fun index(list,n)=
= if n=0 then hd(list) else index(tl(list),n-1);
val index = fn : 'a list * int -> 'a

index([1,2,3,4,5],2);
val it = 3 : int

index([1,2,3,4,5],0);
val it = 1 : int

在这个网站上,仅提供代码的答案通常不被看好。您能否编辑您的答案,包括一些注释或解释您的代码?解释应该回答以下问题:它是做什么的?它是如何做到的?它去哪里?它是如何解决 OP 的问题的?请参阅:如何回答。谢谢! - Eduardo Baitello

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接