【问题标题】:reversing a list in OCaml using fold_left/right使用 fold_left/right 反转 OCaml 中的列表
【发布时间】:2011-11-14 23:28:42
【问题描述】:

更新 - 解决方案

感谢 jacobm 的帮助,我想出了一个解决方案。

// Folding Recursion
let reverse_list_3 theList = 
    List.fold_left (fun element recursive_call -> recursive_call::element) [] theList;;

我正在学习 OCaml(用于类)中的不同递归方式,并且为了一些练习,我正在编写一个函数来使用不同的递归样式来反转列表。

// Forward Recursion
let rec reverse_list_forward theList =
    match theList with [] -> [] | (head::tail) -> (reverse_list_1 tail) @ [head];;

// Tail Recursion
let rec reverse_list_tail theList result =
    match theList with [] -> result | (head::tail) -> reverse_list_2 tail (head::result);;

现在,我正在尝试使用 List.fold_left 编写反向函数,但我被卡住了,无法弄清楚。我将如何使用折叠来编写这个反向函数?

另外,如果有人对函数式编程、不同类型的递归、高阶函数等有很好的参考,将不胜感激:)

【问题讨论】:

    标签: recursion functional-programming ocaml higher-order-functions fold


    【解决方案1】:

    我发现将折叠操作视为对一系列操作的概括很有帮助

    a + b + c + d + e
    

    fold_right (+) 0 以右关联方式应用 + 操作,使用 0 作为基本情况:

    (a + (b + (c + (d + (e + 0)))))
    

    fold_left 0 (+) 以左关联方式应用它:

    (((((0 + a) + b) + c) + d) + e)
    

    现在考虑如果在左右折叠中将 + 替换为 ::0 替换为 [] 会发生什么情况。


    fold_leftfold_right 的工作方式视为“替换”列表中的::[] 运算符也可能很有用。例如,列表[1,2,3,4,5] 实际上只是1::(2::(3::(4::(5::[])))) 的简写。将fold_right op base 视为让您“替换”::op[]base 可能很有用:例如

    fold_right (+) 0 1::(2::(3::(4::(5::[]))))
    

    变成

    1 + (2 + (3 + (4 + (5 + 0))))
    

    :: 变为 +[] 变为 0。从这个角度来看,很容易看出fold_right (::) [] 只是将您的原始列表返回给您。 fold_left base op 做了一些更奇怪的事情:它将列表周围的所有括号改写为另一个方向,将 [] 从列表的后面移动到前面,then 替换 :: op[]base。比如:

    fold_left 0 (+) 1::(2::(3::(4::(5::[]))))
    

    变成

    (((((0 + 1) + 2) + 3) + 4) + 5)
    

    使用+0fold_leftfold_right 产生相同的结果。但在其他情况下,情况并非如此:例如,如果您使用 - 而不是 +,结果会有所不同:1 - (2 - (3 - (4 - (5 - 0)))) = 3,但是 (((((0 - 1) - 2) - 3) - 4) - 5) = -15。

    【讨论】:

    • 是最嵌套的()首先评估?
    • 在 OCaml 中是的,但严格来说,何时评估并不重要。您只需要考虑操作的分组方式。
    • 我的意思是哪个添加是最深层次的递归,即当我达到基本情况时?
    • 是的,没错。我还刚刚编辑了我的回复,以提供另一个可能会有所帮助的观点。
    • 看看我的解决方案...如果您有 cmets,请告诉我!感谢您的帮助!
    【解决方案2】:
    let rev =
      List.fold_left ( fun lrev b ->
        b::lrev
      ) [];;
    

    测试:

    # rev [1;2;3;4];;
    - : int list = [4; 3; 2; 1]
    

    【讨论】:

      猜你喜欢
      • 2014-06-18
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多