【问题标题】:Removing element of list with forward recursion使用前向递归删除列表的元素
【发布时间】:2015-06-11 10:30:20
【问题描述】:

我正在编写一个程序来删除第一个适合谓词的元素。

remove' (fun x -> x = 2) [1;3;2;4;2] => [1;3;4;2]

问题是:如何用前向递归编写它?可能吗?使用尾递归,这不是问题。如果它们不适合谓词,我只需将下一个元素添加到 acc。

我在想

List.fold_right,

但也许有不同的方法可以做到这一点?

【问题讨论】:

    标签: recursion functional-programming ocaml


    【解决方案1】:

    没有“前向递归”这样的东西。尾递归定义了一种特殊的递归,它发生在尾部位置。当你想引用一个不在尾部位置的递归时,你称之为“非尾部递归”

    在您指定的代码中根本没有递归。因此,我建议您首先尝试编写remove_if 函数并尝试确定它是尾还是非尾。

    更新

    我通常尽量不为别人解决作业,但在这种情况下,我会先给你一个最常见的remove_if函数定义:

     let rec remove matches = function
        | [] -> []
        | x :: xs when matches x -> remove matches xs
        | x :: xs -> x :: remove matches xs
    

    这个函数中有两次递归:

    | x :: xs when matches x -> remove matches xs
                                ^^^^^^^^^^^^^^^^^
                                last expression - 
                                tail recursion
    
    | x :: xs -> x :: remove matches xs
                      ^^^^^^^^^^^^^^^^^
                      not the last - 
                      non tail recursive
    

    所以,最后一种情况需要澄清一下:在x 可以添加到remove matches xs 的结果之前,需要评估后一个表达式。这意味着计算机需要在某处存储x,以等待remove matches xs 被评估。

    所以,没有有趣的部分,你有一个非尾递归版本。现在,尝试递归地实现它。有fun

    【讨论】:

    • 我在 stackoverflow 上阅读了“前向递归”。对不起,如果我弄错了。关键是,我必须编写“非尾递归”和“尾递归”删除函数。正如我所说,“非尾递归”算法对我来说是个问题。我不知道如何使它工作。
    • 实际上,我认为您应该首先尝试编写remove_if 函数的任何实现。 (通常的定义其实是非尾递归的,所以尾递归更难写)。而且,据我了解,不能用库函数写remove_if,需要用到递归
    • 好的,既然您迷失在术语中,我向您展示了一个简单的尾递归实现示例。
    • 折叠就足够了,只需let remove_if p l = List.fold_right (fun e a -> if p e then a else e::a) l []。当然,这不是 OP 要求的仅删除一个操作。 (fold_right 也可以,但很丑。)
    • 使用累加器是实现尾递归的一种特殊方法,还有其他方法,例如继续传递。
    【解决方案2】:

    ivg 解决方案对我有很大帮助,但我需要对其进行一些升级。我的回答是:

     let remove' p xs =
       let rec remove_guard p xs g =
          match xs with 
            [] -> []
          | hd::tl -> if (p hd && g = 1) then remove_guard p tl 0 
                      else  hd::remove_guard p tl g
     in remove_guard p xs 1
    

    也许不是最好的,但它只删除了一个元素。

    感谢大家的帮助。我真的很感激。

    【讨论】:

    • 不错,但可以做得更好,而不是在第一次匹配后继续递归与保护标志(顺便说一句,有一个bool类型),你可以选择不完全递归,因为结果已经准备好了
    • 你说得对。你是我的英雄! :D 再次感谢!它不仅是关于家庭作业,而且我真的很喜欢函数式编程(我正在使用 Python 编程,它的功能很差,但仍然在编程。)它帮助我发展我的技能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-06
    • 2021-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    • 1970-01-01
    相关资源
    最近更新 更多