如何解决匿名函数参数在 SML 的 foldl 中的位置
我需要编写一个函数,它接受一个字符串列表并找到列表中最大的字符串。在平局的情况下,它应该返回最接近列表末尾的字符串。问题是它需要使用 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 对问题的回答最多,但没有直接解决问题中的这一陈述。
由于匿名函数是按名称访问元素而不是 位置,为什么这会有所不同?
foldl
接受一个函数,该函数将一个 tuple 作为它的参数,这是位置。
如果我们真的想实现这一点,我们可以定义一个以记录作为参数的折叠函数:
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,4]
得到同样的结果。
但是 namedFold
的类型是 fn :({acc: 'a,x: 'b} -> 'a) -> 'a -> 'b list -> 'a
并且基本上不可能轻松地将现有函数传递给它。使用 foldl
的定义方式,我们可以轻松地将之前对 namedFold
的调用重写为:
foldl op+ 0 [1,4]
因为 op+
与 foldl
的第一个参数具有相同的签名。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。