4

给定以下表达式来对数字的 IEnumerable 求和:

let sum l = l |> Seq.reduce(+)  //version a

是否有可能消除争论——像这样?

let sum = Seq.reduce(+)    //version b

我从 F# 编译器 (FS0030) 中得到一个错误,我似乎记得曾经看过一些关于“eta 转换”的内容,但不幸的是,我对 lambda calc 的了解太有限,无法理解 eta 转换是如何涉及的。

可以像版本 b 中那样消除论点吗?

有人可以向我指出可以解释 eta 转换以及它将如何在这段特定代码中发挥作用的文献吗?

FS0030:

标准输入(1,5):错误 FS0030:值限制。值 'sum' 已被推断为具有泛型类型 val sum : ('_a -> int) when '_a :> seq 将参数明确地传递给 'sum' 或者,如果您不打算将其设为泛型,添加类型注释。

4

3 回答 3

8

“Eta 转换”只是意味着添加或删除参数。您遇到的问题称为值限制。在 ML 语言中,声明为值的值,即。没有显式参数声明,不能有泛型类型,即使它有一个函数类型。这里有一些相关的文献。这个想法是为了防止 ref 单元格保存不同类型的值。例如,如果没有值限制,则允许以下程序:

let f : 'a -> 'a option =
    let r = ref None
    fun x ->
        let old = !r
        r := Some x
        old

f 3           // r := Some 3; returns None : int option
f "t"         // r := Some "t"; returns Some 3 : string option!!!

正如 kvb 所说,如果您不打算将函数设为泛型,则可以添加类型签名并使用无点样式。

于 2013-10-01T14:01:56.033 回答
5

无点函数是一个值。
正如其他答案所说,F# 不允许泛型。但是,它完全允许泛型函数sum让我们通过添加一个假unit参数来转换成一个函数:

let sum_attempt1() = Seq.reduce (+)
let v1 = [1.0; 2.0]     |> sum()    // float
// inferred by first usage:
// val sum_attempt1: unit -> (seq<float> -> float)

这有效,尽管它还不是通用的。标记函数inline可以解决问题:

let inline sum() = Seq.reduce (+)
// val sum: unit -> (seq<'a> -> 'a)

// Use
let v1 = [1; 2]         |> sum()    // int
let v2 = [1.0; 2.0]     |> sum()    // float
let v3 = ["foo"; "bar"] |> sum()    // string
于 2013-10-01T18:54:02.850 回答
5

您可以以无点样式执行此操作,但需要添加(单态)类型注释:

let sum : int seq -> int = Seq.reduce (+)
于 2013-10-01T14:00:14.623 回答