Ono*_*cci 4 f# lambda-calculus pointfree
给出以下表达式来总结一个IEnumerable数字:
let sum l = l |> Seq.reduce(+) //version a
Run Code Online (Sandbox Code Playgroud)
有可能消除这个论点 - 就像这样吗?
let sum = Seq.reduce(+) //version b
Run Code Online (Sandbox Code Playgroud)
我从F#编译器(FS0030)得到一个错误,我似乎记得曾经看过有关"eta转换"的内容,但遗憾的是我对lambda calc的了解太少,无法跟踪如何涉及eta转换.
参数可以像版本b一样被删除吗?
有人请指点文献来解释eta转换以及它将如何在这段特殊代码中发挥作用吗?
FS0030:
stdin(1,5):错误FS0030:值限制.值'sum'被推断为具有泛型类型val sum:('_a - > int)当'_a:> seq要么使'sum'的参数显式,要么如果你不打算使它是通用的,添加类型注释.
"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!!!
Run Code Online (Sandbox Code Playgroud)
正如kvb所说,如果你不打算将该函数设置为泛型,那么你可以添加一个类型签名并使用无点样式.
您可以使用点自由样式执行此操作,但需要添加(单态)类型注释:
let sum : int seq -> int = Seq.reduce (+)
Run Code Online (Sandbox Code Playgroud)
无点函数是一个值。
正如其他答案所说,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)
Run Code Online (Sandbox Code Playgroud)
这是可行的,尽管它还不是通用的。标记该函数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
Run Code Online (Sandbox Code Playgroud)