【问题标题】:SML - error in finding elements in listSML - 在列表中查找元素时出错
【发布时间】:2017-02-03 14:40:03
【问题描述】:

我是 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) 否则返回 (x,y-1)。我使用了一个while循环和一个计数器。计数器首先设置为 y-1,如果找到 (x,counter),则在 while 循环中,计数器的值将减小。最后,如果 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

怎么了?

【问题讨论】:

    标签: sml


    【解决方案1】:

    以下是一些反馈:

    1. (错误) 正如 Andreas Rossberg 所说,break 不存在。但是如果你使用(),当y > 1 并且谓词评估为假时,循环不会终止。您可能想通过设置counter := 0 或counter := -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 更改为什么。

    根据您在代码下方的描述,这是一个建议的实现,虽然我仍然不能完全确定我理解这个函数的用法:

    (* 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 是否是某种垂直维度,因此可能有更好的名称。 (verticalLineExists?verticalPathClear?) 也许更通用的函数会有更好的名称,例如一个拿了两个点,发现它们之间的界限很清楚。

    【讨论】:

      【解决方案2】:

      ML 中没有break。你可能只是想在那里写()。此外,您需要在第 3 行的 ref 参数周围加上括号。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-06
        • 1970-01-01
        • 2013-12-18
        • 2018-09-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-11
        相关资源
        最近更新 更多