关于参数为列表的F#函数参数的Noob问题

时间:2018-12-27 22:59:41

标签: f#

我正在尝试在F#中创建函数,在下图中,我正在尝试创建一个函数,该函数接受一个float列表并求和该列表中的值。我不知道如何在函数中将列表作为参数传递,所以我尝试使用此方法来获取列表的头,但是代码不起作用:

let sumlist l=
    printf "%f" l.Head

然后我看到有人这样做:

let sumlist l:float=
    match l with
    | [] -> 0.0
    | e::li -> e + sumlist li

l:float是将列表传递给函数的方式吗?像l:string这样的字符串列表?

但是我看到列表l具有l.Head函数来返回列表中的第一个元素(似乎我们无法像数组一样访问列表中的任意元素),但是

let sumlist l:float= 
    printfn "%f" l.Head 

给出类型不匹配错误。

我也不理解所提供的递归代码,我不理解这一行

| e::li -> e + sumlist li

什么是::?和李?

谢谢您为我澄清一下!

enter image description here

2 个答案:

答案 0 :(得分:1)

因此,第一个示例不返回任何内容,这是因为您正在调用printfn,该命令会打印到控制台而不是返回您的类型。 e :: li这里表示一个列表,其中e是头,li是列表的其余部分。 ::这里让编译器知道您要解构列表。

//fully annotated
let s (l: float list) :float = 
    l.Head
//here the types can be inferred without any annotation
let rec sumlist l = 
    match l with
    | [] -> 0.0
    | e::li -> e + sumlist li

s [0.7]
//returns 0.7

sumlist [0.4;0.5;0.6]
//returns 1.5

在我的第一个示例中,如果尝试删除类型注释,则会发现出现错误。这是因为l.Head的类型是模棱两可的,否则您是否在字符串列表(浮点数)上调用了l.Head?在我提供的sumlist函数中,您可以看到我不需要注释,这是因为我将它们加起来并限制了类型。

就个人而言,我强烈建议始终对类型进行注释。 (l : float list)(l: list<float>)是说我的输入是浮点数列表的一种方式,而:float最后是我们说返回类型是浮点数的方式。您会注意到我在递归函数上放置了rec关键字,最好在进行递归函数时显式声明。

答案 1 :(得分:1)

语法问题

  

l:float是将列表传递给函数的方式吗?

不。多数情况下,编译器可以确定您在传递列表时未将参数注释为列表,但是如果没有通过注释,则注释为

l : 'a list // where 'a is generic type
// OR
l : float list // where type is specified as float
  

什么是::?和李?

当模式匹配列表时,[]匹配到空列表,此处用作递归结束条件。另一个匹配将头(e)与列表的其余部分(尾)(li)分开。如果列表中只有一项,则li的值为[]。

递归代码的附加说明:例如,您缺少递归关键字 rec

let rec sumlist ...

递归函数实现

最简单的方法是使用sum function of List例如。

[0.4; 0.5; 0.6] |> List.sum // Returns 1.5

但是,如果要自己创建此函数,请考虑使用tail-recursion以获得更好的性能,并避免使用较大的输入列表来避免堆栈溢出。

let sumlist (values : float list) =
    let rec sum (acc : float) (remaining : float list) =
        match remaining with
        | [] -> acc
        | head :: tail -> sum (acc + head) tail
    sum 0. values

被称为

[0.4; 0.5; 0.6] |> sumlist // Returns 1.5

与常规递归不同的是,每个递归都计算自己的值,并且不依赖于其他递归尚未完成计算。