匿名函数的参数在 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_string2
,foldl
函数将模式匹配你的列表与 x::xs,其中 x
是“ Apple” 和 xs
是 ["ball", "Bpple"]。当您使用 f(x, acc)
计算更新的累加器时,x
和 acc
被交换。换句话说,在你的匿名函数(带有反向参数)中,你会假设第一个参数是 ””
第二个参数是 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
的第一个参数具有相同的签名。
我需要编写一个函数,它接受一个字符串列表并在列表中找到最大的字符串。在平局的情况下,它应该 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_string2
,foldl
函数将模式匹配你的列表与 x::xs,其中 x
是“ Apple” 和 xs
是 ["ball", "Bpple"]。当您使用 f(x, acc)
计算更新的累加器时,x
和 acc
被交换。换句话说,在你的匿名函数(带有反向参数)中,你会假设第一个参数是 ””
第二个参数是 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
的第一个参数具有相同的签名。