SML - 列表替换函数的迭代翻译

发布于 2024-10-21 00:40:11 字数 672 浏览 1 评论 0原文

我相信我在将第一个函数转换为仅使用赋值和循环方面处于正确的轨道上。我知道这违背了函数式编程,但这是教授想要的。

递归函数:

fun sub (x, y, []) = []
  | sub (x, y, z::zz) = if x = z then y::sub(x, y, zz)
            else z::sub(x, y, zz);

迭代翻译:

fun sub2 (x, y, z) =
    let val ret = ref []; val temp = z;
    in
        while !temp <> []
        do (if x = hd(!temp) then ret := !ret::y; temp := tl(!temp)
            else ret := ret::hd(!temp); temp := tl(!temp));
        !ret;
    end;

我在 smlnj 上运行时收到以下错误。第一个在 do 线上,第二个在最后。

错误:语法错误:将 END 替换为 EQUALOP

错误:在 EOF 处发现语法错误

我希望能帮助调试,或者也许有一种更干净的方法来完成此迭代函数。

I believe I'm on the right track in converting my first function to only use assignments and loops. I know this is against functional programming, but it's what a professor wants.

Recursive function:

fun sub (x, y, []) = []
  | sub (x, y, z::zz) = if x = z then y::sub(x, y, zz)
            else z::sub(x, y, zz);

Iterative translation:

fun sub2 (x, y, z) =
    let val ret = ref []; val temp = z;
    in
        while !temp <> []
        do (if x = hd(!temp) then ret := !ret::y; temp := tl(!temp)
            else ret := ret::hd(!temp); temp := tl(!temp));
        !ret;
    end;

I receive the following errors running on smlnj. The first on the line with the do, and second being at the end.

Error: syntax error: replacing END with EQUALOP

Error: syntax error found at EOF

I'd appreciate help debugging or perhaps a cleaner way to accomplish this iterative function.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

年华零落成诗 2024-10-28 00:40:11

为什么哦为什么他不想要那个?没关系...

有很多问题。

  1. 您在不需要的地方使用了许多分号。然而,这不是语法错误。
  2. 您忘记了 if 语句中的序列 (exp1; exp2) 周围的括号。只允许排除 let..in..end 表达式的“in”部分中的括号。
  3. 您将 temp 作为引用类型(使用 := 和 !)。然而,您还没有将其设为参考。这意味着您的输入变量 z 必须作为参考给出。如果这是您想要的,那么它与原始的子功能不匹配。
  4. 原始子函数将自身限制为相等类型。但是,如果情况并非如此,那么您的 !temp <> null 将进行限制。使用 List.null 函数代替。
  5. 当序列停止时,最后一个 !ret; 处的分号不应该出现,否则 end 将成为序列的一部分,从而失败。
  6. 您忘记在条件的其他部分取消引用ret
  7. 您已切换 cons (::) 的参数。 Cons 的类型为 'a * 'a list,因此采用一个元素,然后采用一个元素列表。解决此问题并仍然保留元素顺序的一种方法是使用追加 (@) 函数,然后将要追加的元素放置在单例列表中。然而,有很多方法可以更好地处理这个问题,因为追加函数在大列表上的表现非常差。

以下是一个有效的函数:

fun sub2 (x, y, z) =
let 
  val ret = ref []
  val temp = ref z
in
  while not (null (!temp)) do 
    if x = hd(!temp) then 
      (ret := !ret @ [y]; 
       temp := tl(!temp))
    else 
      (ret := !ret @ [hd(!temp)]; 
       temp := tl (!temp));
  !ret
end

这​​里可以改进的一个明显的事情是您始终使用相同的值更新 temp。所以这个可以排除掉。并且条件可以改为 case

fun sub2 (x, y, z) =
    let 
      val ret = ref []
      val temp = ref z
    in
      while not (null (!temp)) do       
        (case x = hd(!temp) of
          true => ret := y :: !ret
        | false => ret := hd(!temp) :: !ret
       ;temp := tl (!temp));         
      rev (!ret)
    end

特别注意元素如何不附加而是添加到结果列表中,而是放置在前面,然后在最后将结果列表反转以获得正确的顺序。这将使您在大型列表上获得更好的性能。然而,当您在 SML 中采用命令式风格时,还有更好的方法可以做到这一点。

正如您已经看到的,它可以通过函数式方式完成。但它也可以做得更简单。使用地图考虑以下内容。

fun sub3 (x, y, zs) = map (fn z => if z = x then y else z) zs

Why oh why would he ever wan't that? Never mind...

There are quite a few problems.

  1. You are using way to many semicolons, where they are not needed. This is however not a syntactic error.
  2. You have forgot parenthesis around your sequence (exp1; exp2) in your if-statement. It is only allowed to exclude the parenthesis in the "in" part of a let..in..end expression.
  3. You are refering to temp as a ref type (using := and !). You have however not made it a ref. This means that your input variable z will have to be given as a reference. If this is what you intend, then it doesn't match the original sub-function.
  4. The original sub-function restricts itself to equality types. However if this was not the case, then your !temp <> null will make the restriction. It would be "best practice" to use the List.null function instead.
  5. The semicolon at the last !ret; should not be there as your sequence stops, else end will become part of the sequence which will fail.
  6. You have forgotten to dereference ret in you else part of the condition.
  7. You have switched the arguments of cons (::). Cons has type 'a * 'a list and thus takes an element and then a list of elements. One way of fixing this and still preserving the order of elements is to use the append (@) function and then placing the element to append in a singleton list. However there are so many ways of handling this in a better way as the append function performs very poorly on big lists.

Following is a function that works:

fun sub2 (x, y, z) =
let 
  val ret = ref []
  val temp = ref z
in
  while not (null (!temp)) do 
    if x = hd(!temp) then 
      (ret := !ret @ [y]; 
       temp := tl(!temp))
    else 
      (ret := !ret @ [hd(!temp)]; 
       temp := tl (!temp));
  !ret
end

One obvious thing that can be improved here is that you always update temp with the same value. So this could be factored out. And the condition could be changed to a case instead

fun sub2 (x, y, z) =
    let 
      val ret = ref []
      val temp = ref z
    in
      while not (null (!temp)) do       
        (case x = hd(!temp) of
          true => ret := y :: !ret
        | false => ret := hd(!temp) :: !ret
       ;temp := tl (!temp));         
      rev (!ret)
    end

Especially notice how the elements are not appended but to the resulting list, but placed in the front and then at the end the resulting list is reversed to get the correct order. This will give you much better performance on big lists. There are however still better ways of doing this when you go imperative style in SML.

As you have already seen, it can be done in a functional way. But it could also be done simpler. Consider the following using map.

fun sub3 (x, y, zs) = map (fn z => if z = x then y else z) zs
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文