匿名函数的参数在 SML 的 foldl 中的位置

Position of anonymous function’s parameters in SML’s foldl

我需要编写一个函数,它接受一个字符串列表并在列表中找到最大的字符串。在平局的情况下,它应该 return 最接近列表末尾的字符串。问题是它需要使用 List.foldl 遍历列表,并且除了 List,foldl 的库函数中的那些之外不能使用递归调用。 以下代码工作正常。

fun longest_string2 str_list =
     List.foldl(fn (x, acc) => if String.size x >= String.size acc then x else acc) "” str_list

如果我在 REPL 中 运行 longest_string2 ["Apple", "ball", "Bpple”];,我得到 val it = "Bpple" : string 但是,如果我如下反转匿名函数的参数,我会得到 val it = "Apple" : string。 由于匿名函数是按名称而不是位置访问元素,为什么这会有所不同?

List.foldl的定义是

fun foldl (f: 'a*'b->'b) (acc: 'b) (l: 'a list): 'b =
  case l of
    [] => acc
  | x::xs => foldl f (f(x,acc)) xs

如果你反转匿名函数的参数,你的函数将变成如下:(如果我误解了你的问题请纠正我)

fun longest_string2 str_list =
     List.foldl(fn (acc, x) => if String.size x >= String.size acc then x else acc) "” str_list

如果你现在将 ["Apple", "ball", "Bpple”] 作为参数传递给 longest_string2foldl 函数将模式匹配你的列表与 x::xs,其中 x 是“ Apple” 和 xs 是 ["ball", "Bpple"]。当您使用 f(x, acc) 计算更新的累加器时,xacc 被交换。换句话说,在你的匿名函数(带有反向参数)中,你会假设第一个参数是 ”” 第二个参数是 Apple 但 List.foldl 的实现将通过 f(“Apple”, “”)。在这种情况下,您的匿名函数会将 “Apple” 标记为 “acc”,将 “” 标记为 “x”

@3123 回答了最多的问题,但没有直接解决问题中的这个陈述。

Since the anonymous function is accessing the elements by name and not position, why does this makes difference?

foldl 接受一个函数,该函数以 元组 作为参数,这是位置参数。

如果我们真的想实现这一点,我们可以定义一个以记录作为参数的折叠函数:

fun namedFold _ acc [] = acc
  | namedFold f acc (x::xs) =
      namedFold f (f {acc=acc, x=x}) xs;

然后将其命名为:

namedFold (fn { acc, x } => acc + x) 0 [1,2,3,4]

或如:

namedFold (fn { x, acc } => acc + x) 0 [1,2,3,4]

得到相同的结果。

但是 namedFold 的类型是 fn :({acc: 'a, x: 'b} -> 'a) -> 'a -> 'b list -> 'a 并且基本上不可能轻松地将现有函数传递给它。使用 foldl 定义的方式,我们可以轻松地将之前对 namedFold 的调用重写为:

foldl op+ 0 [1,2,3,4]

因为 op+foldl 的第一个参数具有相同的签名。