简体   繁体   English

了解ML中的foldl

[英]Understanding foldl in ML

I need to write a function that takes a list of strings and finds the largest string in the list. 我需要编写一个函数,它接受一个字符串列表并找到列表中最大的字符串。 The catch is it needs to iterate through the list using List.foldl and cannot use recursive calls except for those in the library function of List,foldl. 问题是它需要使用List.foldl迭代列表,并且不能使用递归调用,除了List,foldl的库函数中的那些调用。

I wrote 我写

fun longest_string1(xs)= 
case xs of 
[] => ""  
| x::xs' => List.foldl((fn (s,x) => if String.size s > String.size x then s else x) "" x,)

with my interpretation being as follows: 我的解释如下:

-take in xs, if xs is empty return an empty string -s in xs,如果xs为空,则返回空字符串

-otherwise for the first item of xs call List.foldl - 另外,xs的第一项调用List.foldl

-List.foldl passes in an anonymous function that checks the length of s, which should represent the accumulator against the head item of the list. -List.foldl传入一个匿名函数,该函数检查s的长度,该函数应代表对应列表头项的累加器。

-Set the initial accumulator to be the empty string and the initial compare value to be the head of the initial list passed in by the higher order function - 将初始累加器设置为空字符串,将初始比较值设置为高阶函数传入的初始列表的头部

However, it does not type check. 但是,它不进行类型检查。

I think my issue is in the understanding of the List.foldl function itself and how exactly it reads in its parameters. 我认为我的问题在于理解List.foldl函数本身以及它如何读取其参数。 Can someone please provide some clarification? 有人可以提供一些澄清吗?

So, for the code you posted: 那么,对于您发布的代码:

  1. You don't need the case for the empty list. 您不需要空列表的大小写。 foldl will take care of that for you. foldl会照顾你的。 Just pass xs to foldl instead of x. 只需将xs传递给foldl而不是x。
  2. foldl is curried, so you shouldn't have parentheses around the parameters. foldl是curried,所以你不应该在参数周围加上括号。

Other than that, it actually looks correct. 除此之外,它实际上看起来是正确的。 Anyway, if you're still not sure how foldl works, here's a really long and thorough explanation ;) 无论如何,如果你仍然不确定foldl是如何工作的,这里有一个非常详尽的解释;)

Okay, let's start with List.foldl. 好的,让我们从List.foldl开始。

val foldl : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b

So, there are three parameters. 所以,有三个参数。 One is a function which we'll worry about later, the second is a value of the same type as the return type , and the last is the list. 一个是我们稍后会担心的函数,第二个是与返回类型相同类型的值最后一个是列表。

So, let's take a simple example - say we have a list of ints, and we want to sum all the numbers. 所以,让我们举一个简单的例子 - 比如我们有一个整数列表,我们想要总结所有数字。 We could do this: 我们可以这样做:

fun sum [] = 0
  | sum (x::xs) = x + sum xs

Or, we can use foldl (I'll write foldl instead of List.foldl from now, because I'm lazy). 或者,我们可以使用foldl(从现在起我会写foldl而不是List.foldl,因为我很懒)。

So, we know that the list is the third parameter. 所以,我们知道列表是第三个参数。 The second should be some sort of starting value, or accumulator, something that would make sense if the list was empty. 第二个应该是某种起始值,或累加器,如果列表为空则有意义。 For a sum, that would be 0. 总和,那将是0。

The first parameter is a function, and this is the tricky part. 第一个参数是一个函数,这是棘手的部分。 The type is: 类型是:

fn : 'a * 'b -> 'b

Okay, so 'a is also the type of the elements in the list, so it makes sense if this is an item from the list. 好的,所以'a也是列表中元素的类型,所以如果这是列表中的项目则有意义。 'b is the type of the starting value and the return value. 'b是起始值返回值的类型。

What actually happens is that foldl calls the function with the first element in the list, and the accumulator. 实际发生的是foldl使用列表中的第一个元素和累加器调用函数。 It then calls itself with the result as the new accumulator, and the rest of the list. 然后它将结果称为累加器和列表的其余部分。 So if we do this: 所以,如果我们这样做:

foldl foo 0 [1,2,3]

It'll do 它会的

foo (1,0)

And then 然后

foldl foo (foo (1,0)) [2,3]

And so on. 等等。

So for summing a list, we'll make the following function: 因此,对于汇总列表,我们将进行以下功能:

fn (x,acc) => x + acc

So we can do this: 所以我们可以这样做:

fun sum xs = foldl (fn (x,acc) => x + acc) 0 xs

Or, even simpler 或者,甚至更简单

val sum = foldl op+ 0

( op+ does the same as the anonymous function I used earlier) op+与我之前使用的匿名函数相同)

Let's walk through it with the list [1,2,3] 让我们一起来看清单[1,2,3]

foldl op+ 0 [1,2,3]
foldl op+ (op+ (1,0)) [2,3] -> foldl op+ 1 [2,3]
foldl op+ (op+ (2,1)) [3]   -> foldl op+ 3 [3]
foldl op+ (op+ (3,3)) []    -> foldl op+ 6 []
6

the following code is the solution for your problem: 以下代码是您的问题的解决方案:

fun longest_string1(xs: string list) = 
    case xs of 
        [] => ""  
        | x::xs' => List.foldl((fn (s,x) => if String.size s > String.size x then s else x)) "" xs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM