这可以用点自由风格表达吗?

时间:2013-10-01 13:46:04

标签: f# lambda-calculus pointfree

给出以下表达式来总结一个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”的参数显式化,或者如果你不打算这样做   通用,添加类型注释。

3 个答案:

答案 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