我需要一个函数来查找实现List.fold
模块的列表的最小元素。我知道我可以使用List.min,但对于这个练习,我需要它是List.fold。到目前为止,我有:
let findMin list min = function
| [ ] -> min
| head::tail -> list |> List.fold( fun acc -> min) //missing conditional inside fold to determine min
我不习惯函数式编程,通常在java中我会做这样的事情:
public int getMin (){
int min = head.data;
Node curr = head.next;
while (! ( curr == NULL ) ){
if ( curr.data < min)
min = curr.data;
curr = curr.next;
}
return min;
}
但由于F#使用不可变常量,我无法重新分配min。我发现了用于计算或求和列表中元素的fold示例,但没有找到最小或最大元素。我在模块内部的条件逻辑方面遇到了问题,如果有人能帮助我,我将不胜感激。提前谢谢。
您不需要处理输入列表为空的情况,因为List.fold
在这种情况下返回初始值。通常我们通过System.Int32.MaxValue
作为初始值。
这里是长版本代码:
let min a b = if a < b then a else b
let minOfList initialValue theList =
theList
|> List.fold
(fun currentMin x ->
let newMin = min currentMin x
newMin)
initialValue
let result = minOfList System.Int32.MaxValue [34; -1; 21; 99]
printfn "%d" result // -1
和短版本代码:
let min a b = if a < b then a else b
let minOfList = List.fold min
let result = minOfList System.Int32.MaxValue [34; -1; 21; 99]
printfn "%d" result // -1
您可以使用累加器作为通常将最小值分配给的值。
对于数组的每个项,fold将累加器和当前项提供给给定的函数。该函数返回的内容将成为新的累加器值。
使用内置的min
功能,您可以编写
let findMin list = List.fold min System.Int32.MaxValue list
min
是应用于每个项目和累加器的函数
System.Int32.MaxValue
是累加器的原始值,种子
您也可以使用List.reduce
,这是相同的,但它使用列表的第一个元素作为种子。
let findMin list = List.reduce min list
理想情况下,您应该将其封装在处理空数组情况的东西中,因为fold
将返回种子值,而reduce
将引发异常。
fold的概念很简单:在列表上迭代一个称为folder
函数的函数。在每次调用中,folder
函数从列表中接收一个元素和一个状态,并返回一个更新的状态。
这与您的命令式代码非常相似:您正在对列表进行迭代,从列表中接收一个元素和变量min
的旧值,每次迭代后都会有一个新值min
。与命令式编程的不同之处在于,folder
函数不会更改状态,而是接收一个状态并返回另一个状态,可以想象,如果您喜欢List.fold
在内部更改变量。
fold的签名是:
List.fold :
folder: 'State -> 'T -> 'State ->
state : 'State ->
list : 'T list
-> 'State
第一个参数是文件夹函数,第二个参数是初始状态,第三个参数是元素列表。结果将是最后一个状态。
所以你的folder
函数应该是这样的:
let folder min currData = ...
你的minimum
函数应该是这样的:
let minimum ls =
ls
|> List.fold folder initial
你这样称呼它:
minimum [ 5 ; 3 ; 8]
|> printfn "%A" // outputs: 3
关于如何处理初始值以及如果列表为空会发生什么,还有一些问题。但我会把这些留给你。
希望这能有所帮助。
感谢大家的帮助,澄清了一些概念。这是最后一个运行的代码段,输入验证是在主函数中完成的。
// this is the folder function List.fold calls, receives the current min and item
let folder a b = if a < b then a else b
// recieves a list and returns the minimum using the List.fold module
let fold list = List.fold (fun acc elem -> folder acc elem) (List.head list) list