如何使用List.fold_left?

时间:2019-05-03 18:28:55

标签: ocaml

我仍在尝试了解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”。

1 个答案:

答案 0 :(得分:0)

List.fold_left实际上是遍历一个列表,将值从一个调用传递到另一个,基本上就像bucket brigade一样,只有一个存储桶,在每次迭代中您都可以查看存储桶,拿东西在那里,放一些新东西。

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

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

,它带有三个参数,即函数f,初始值initelements的列表。为{{1}的每个元素f调用函数xelements,其中f acc xacc,如果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 fst来访问该对元素,而是直接在参数列表中解构了元组。这使代码更容易理解和缩短。

应用于每个步骤的函数带有两个参数,snd是存储桶(通常称为“累加器”),列表的元素是一对sum就我们而言。我们将(k,r)乘以k变量的值并乘以幂x,然后将结果加到累加器上。

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

r

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