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

时间:2017-02-03 14:40:04

标签: 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)) 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),计数器的值将减小。最后,如果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

出了什么问题?

2 个答案:

答案 0 :(得分:1)

ML中没有break。你可能只想在那里写()。此外,您需要在第3行ref的参数周围找到问题。

答案 1 :(得分:1)

以下是一些反馈:

  1. (错误)正如Andreas Rossberg所说,break并不存在。但是如果使用(),则循环在y > 1时终止并且谓词的计算结果为false。你可能想要打破"打破"设置counter := 0counter := -1,具体取决于您希望后续if !counter = 0 ...做什么。

  2. (错误)正如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.

  3. 这不是很容易理解或很强大。我试着以我能想到的最简单的方式运行它,

    val test1 = move (1,1,[])
    

    但这是一个奇怪的基本情况,不是由循环处理的。如果我稍微改变数字,

    val test2 = move (5,6,[])
    

    然后返回(5,6)(5,5),具体取决于您将break更改为的内容。

  4. 根据您在代码下方的说明,这是一个建议的实现,虽然我还不完全确定我理解这个功能的使用:

    (* 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是否是某种垂直维度,因此可能还有更好的名称。 (verticalLineExistsverticalPathClear?)也许更通用的功能会有更好的名称,例如一个拿了两分,看到他们之间的界线清晰。