【问题标题】:SML - Iterative translation of list replace functionSML - 列表替换功能的迭代翻译
【发布时间】:2011-07-10 03:40:31
【问题描述】:

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

递归函数:

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 发现语法错误

我会很感激帮助调试或者可能是一种更简洁的方式来完成这个迭代功能。

【问题讨论】:

    标签: loops sml iteration


    【解决方案1】:

    为什么哦,为什么他不想那样呢?没关系...

    有很多问题。

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

    以下是一个有效的功能:

    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
    

    【讨论】:

    • 哇,谢谢。这些例子提供了很多。缩进和分号的使用在课堂上以一种奇怪的方式进行。您介绍的不同功能将对我有很大帮助。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2012-02-01
    • 2016-06-07
    • 2015-05-19
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    • 2017-06-25
    • 1970-01-01
    相关资源
    最近更新 更多