这可以用无点风格表达吗?
Posted
技术标签:
【中文标题】这可以用无点风格表达吗?【英文标题】:Can this be expressed in point free style? 【发布时间】:2013-10-07 17:06:21 【问题描述】:给定以下表达式来对数字的 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:值限制。值“总和”已 推断具有泛型类型 val sum : ('_a -> int) when '_a :> seq 将参数明确地传递给 'sum' 或者,如果您不打算这样做 泛型,添加类型注释。
【问题讨论】:
l
在版本 a 中做了什么?您能否提醒我们(在问题正文中)FS0030
是什么?
您的意思是 let sum l = Seq.reduce (+) l
用于版本 a 吗?
好吧,正如您从错误中看到的(并且可能知道),F# 不允许泛型值。 F# 仅有限支持无点样式。
@petebu 谢谢——代码已修复。
【参考方案1】:
“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 所说,如果您不希望函数是泛型的,那么您可以添加类型签名并使用无点样式。
【讨论】:
或许可以简单的表述为:ML语言中的函数可以是闭包,而且由于ML是静态类型的,所以在使用前必须在引用环境中消除类型的歧义。【参考方案2】:你可以用无点样式来做,但是你需要添加一个(单态)类型注释:
let sum : int seq -> int = Seq.reduce (+)
【讨论】:
谢谢@kvb;我还想知道是否有人可以向我指出有关 eta 转换的更多信息。【参考方案3】:无点函数是一个值。
正如其他答案所说,F# 不允许通用值。但是,它完全允许通用函数。让我们通过添加一个假的unit
参数将sum
转换为一个函数:
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
【讨论】:
有趣的想法——在函数上添加内联。以上是关于这可以用无点风格表达吗?的主要内容,如果未能解决你的问题,请参考以下文章
可以在 VSCode 中获得 pycharm 风格的“使用 Python 控制台运行”功能吗?