【问题标题】:How do I use List.fold_left?如何使用 List.fold_left?
【发布时间】:2019-05-04 03:15:45
【问题描述】:

我仍在尝试了解 fold_left 的具体工作原理。它会像List.iter 这样遍历列表吗?还是我的代码有其他问题?我认为 e 是列表中的元素(所以它是一个元组),fst e 采用元组的第一个元素,snd e 采用元组中的第二个元素。

let rec pow x n = 
    if n < 0 then
        0
    else if n = 0 then
        1
    else 
        x * pow x (n - 1);;    

let polynomial lst = function
    | x -> List.fold_left (fun e -> (fst e) * (pow x (snd e))) 1 lst;;

lst 是一个元组列表,其中每个元组有两个整数并构成一个多项式函数,因此多项式应该返回一个函数。所以应该发生的一个例子是这样的

# let f = polynomial [3, 3; -2, 1; 5, 0];;
val f : int -> int = <fun>
# f 2;; (* f is the polynomial function f(x) = 3x^3 + (-2)x + 5 *)
- : int = 25

但我收到此错误消息

“错误:此表达式的类型为 int,但表达式应为 'a -> int * int”类型。

【问题讨论】:

    标签: ocaml


    【解决方案1】:

    List.fold_left 确实迭代了一个列表,将值从一个调用传递到另一个调用,这基本上就像一个 bucket brigade,只有一个桶,在每次迭代中你可以查看桶,取任何存在的东西并放一些新东西。

    更正式地说,fold_left f init elements 有类型

    val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
    

    它接受三个参数,函数f、初始值initelements的列表。函数 felements 的每个元素 x 调用为 f acc x,其中 acc 要么是 init,如果 x 是列表的第一个元素或上一次调用返回的结果的f。回到我们的类比,它要么是最初的空桶,要么是链中上一个调用传递的桶。

    在您的情况下,桶的作用是所有术语的最终总和。最初,它是空的,然后每个新术语计算 (fst e) * (pow x (snd e)) 并将其添加到存储桶中,以便最后您将获得所有术语的总和,

    let polynomial coeffs x = 
      List.fold_left (fun sum (k,r) -> sum + k * pow x r) 0 coeffs
    

    注意,我没有使用fstsnd 来访问对的元素,而是直接在参数列表中解构元组。这使代码更易于理解且更短。

    应用于每个步骤的函数有两个参数,sum 是桶(它通常被称为“累加器”)和列表的元素,在我们的例子中是一对(k,r)。我们将k 乘以x 变量的值r 的幂,然后将结果添加到累加器中。

    对于具有命令式思维方式的人,以下伪代码1 可能比斗式大队类比更有洞察力:

    def fold_left(user_func, init, elements):
        acc = init
        for elt in elts:
           acc = user_func(acc, elt)
        return acc
    

    1) 与 Python 的任何相似之处纯属巧合:)

    【讨论】:

    • 所以 0 是函数的起始值,并且 (fun sum (k,r) -> sum + k * pow x r) 添加到它?如果我没听错的话。
    • 不客气,fold_left函数的详细解释我加了,官方手册好像没有详细说明。
    猜你喜欢
    • 2015-01-13
    • 2012-12-31
    • 1970-01-01
    • 2012-09-29
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    相关资源
    最近更新 更多