SML-在列表中查找元素时出错

SML-在列表中查找元素时出错,sml,Sml,我是SML的新手。我写了一个函数,它以2 int和一个元组列表作为输入 fun move(x,y,mylist:(int * int)list): NOxNO = let val counter = ref y-1 in if y=1 then (x,y) else ( while !counter > 0 do ( if List.exists (fn s => s = (x,!counter)

我是SML的新手。我写了一个函数,它以2 int和一个元组列表作为输入

fun move(x,y,mylist:(int * int)list): NOxNO =
    let
      val counter = ref y-1
    in
      if y=1 then (x,y)
      else (
        while !counter > 0 do (
          if List.exists (fn s => s = (x,!counter)) mylist
          then counter := !counter - 1
          else break
        );
        if !counter = 0 then (x,y) else (x,y-1)
      )
    end
我可能有语法错误,因为我是初学者。函数试图做的是:它将检查列表以查找第一个元素为x,第二个元素从1到y-1的所有元组(元组如下:(x,1)(x,2)…(x,y-1)),如果列表中存在所有元组,它将返回(x,y)else(x,y-1)。我用了一个while循环和一个计数器。计数器首先设置为y-1,在while循环中,如果找到(x,计数器),计数器的值将减小。最后,如果counter=0,则表示我们找到了所有元组。运行程序后,我遇到以下错误:

Caught Error ../compiler/TopLevel/interact/evalloop.sml:296.17-296.20
             ../compiler/TopLevel/interact/evalloop.sml:44.55
             ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27

怎么了?

在ML中没有
中断
。您可能只想在那里编写
()
。此外,您还需要对第3行中的
ref
参数进行排列。

以下是一些反馈:

  • (错误)正如Andreas Rossberg所说,
    break
    不存在。但是如果使用
    ()
    ,则循环不会在
    y>1
    时终止,谓词的计算结果为false。您可能希望通过设置
    计数器:=0
    计数器:=-1
    来“中断”,这取决于您希望后续
    如果!计数器=0…
    要执行的操作

  • (错误)正如Andreas Rossberg所说,
    ref y-1
    给出了以下类型的错误:

    ! Toplevel input:
    ! val r = ref y-1;
    !               ^
    ! Type clash: expression of type
    !   int
    ! cannot have type
    !   int ref
    
    这是因为函数应用程序(
    ref y
    )绑定比中缀运算符(
    y-1
    )更紧密。您的意思是
    ref(y-1)
    ,因为您不能从引用中减去1

  • 这不是很容易理解,也不是很可靠。我试着用我能想到的最简单的方法运行它

    val test1 = move (1,1,[])
    
    但这是一个奇怪的基本情况,不由循环处理。如果我稍微改变一下数字

    val test2 = move (5,6,[])
    
    然后它返回
    (5,6)
    (5,5)
    ,具体取决于您将
    分解为什么

  • 根据您在下面代码中的描述,这里是一个建议的实现,尽管我还不能完全确定我是否理解此函数的用法:

    (* verticalPointsExist (x, y, ps) checks that
     * (x,1), (x,2), ..., (x,y-1) are all in ps. *)
    fun verticalPointsExist (_, 0, _) = true
      | verticalPointsExist (x, y, ps) = List.exists (fn p => (x,y) = p) ps
                                 andalso verticalPointsExist (x, y - 1, ps)
    
    fun move (x, y, ps) =
        if verticalPointsExist (x, y, ps) then (x,y) else (x,y-1)
    
    我所作的考虑:

    • 使用递归而不是迭代

    • 将检查部分拆分为一个助手函数,这样
      move
      就不会做两件事

    • 给函数起个好名字,这样代码读起来就更容易了。因为我不知道这个领域,我真的在猜测
      y
      是否是某种垂直维度,所以可能还有更好的名字。(
      verticalPathClear
      verticalPathClear
      ?)也许更通用的函数会有更好的名称,例如,取两个点并看到它们之间的直线清晰的函数