给出以下表达式来总结一个IEnumerable数字:
let sum l = l |> Seq.reduce(+) //version a
是否有可能消除这个论点 - 就像这样?
let sum = Seq.reduce(+) //version b
我从F#编译器(FS0030)收到错误,我似乎记得曾经看过有关“eta转换”的内容,但遗憾的是我对lambda calc的了解太少,无法跟踪如何进行eta转换。
可以像在版本b中一样消除参数吗?
有人请指点文献来解释eta转换以及它将如何在这段特殊代码中发挥作用吗?
FS0030:
stdin(1,5):错误FS0030:值限制。值'sum'已经存在 推断为具有泛型类型 val sum:('_ a - > int)当'_a:> seq将“sum”的参数显式化,或者如果你不打算这样做 通用,添加类型注释。
答案 0 :(得分:7)
“Eta转换”只是意味着添加或删除参数。你遇到的问题叫做价值限制。在ML语言中,声明为值的值,即。声明没有显式参数,不能有泛型类型,即使它有一个函数类型。 Here是一些相关文献。这个想法是为了防止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所说,如果你不打算将该函数设置为泛型,那么你可以添加一个类型签名并使用无点样式。
答案 1 :(得分:5)
你可以点自由风格,但你需要添加(单态)类型注释:
let sum : int seq -> int = Seq.reduce (+)
答案 2 :(得分:4)
无点函数是一个值
正如其他答案所说,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