【发布时间】:2021-05-10 18:50:57
【问题描述】:
如何通过在调用点指定参数名称来调用F#函数?
我尝试了以下方法:
let add x y =
x + y
add (x = 10) (y = 10) // How to specify the name x and y when calling add?
但它给出了这个错误:
错误 FS0039:未定义值或构造函数“x”。
【问题讨论】:
标签: f#
如何通过在调用点指定参数名称来调用F#函数?
我尝试了以下方法:
let add x y =
x + y
add (x = 10) (y = 10) // How to specify the name x and y when calling add?
但它给出了这个错误:
错误 FS0039:未定义值或构造函数“x”。
【问题讨论】:
标签: f#
您不能使用命名参数调用let-bound 函数。仅允许用于类中的方法
命名参数只允许用于方法,不允许用于 let-bound 函数、函数值或 lambda 表达式。
从技术上讲,您可以声明静态类并从中使用方法,但我认为这是错误的。只是错了。不要这样做
[<AbstractClass; Sealed>]
type MathOperations =
static member Add (x, y) = x + y
open type MathOperations
[<EntryPoint>]
let main argv =
Add(x = 3, y = 4)
|> printfn "%d"
0
【讨论】:
这个问题一开始也让我很困惑。函数和方法不一样。
member _.Add x y = x + y 甚至混合样式声明 member _.Add3 (x: int, y: int) (z: int) = x + y + z 但这些方法不能使用命名参数调用 o.Add3 (y=2, x=1) 3 ?
在 JavaScript 中,可以使用对象字面量作为参数来模拟命名参数。让我们尝试在 F# 中做同样的事情,使用元组或记录:
1.元组: 方法参数通过一个元组一次性提供。我们可以使用元组作为函数参数并使用命名参数调用函数吗?没有❌
let add (x, y) = x + y
add (x = 1, y = 2) // ?
// ~ Error FS0039: The value or constructor 'x' is not defined
2。匿名记录:由于匿名记录解构的实际限制,不可能 ❌
let add {| X = x; Y = y |} = x + y
// ~~ Error FS0010: Unexpected symbol '{|' in pattern
3。命名记录:⚠️
type AddParam = { x: int; y: int }
let add { x = x; y = y } = x + y
add { x = 1; y = 2 }
这样,我们可以命名参数并选择它们的顺序({ y = 2; x = 1 },但我们失去了部分应用程序。所以它不是惯用的→应该避免,除非在特定情况下。
4.单例DU:?
如果我们只关心参数命名而不关心参数重新排序,我们可以使用可区分联合,尤其是单例 DU:
type XParam = X of int
type YParam = Y of int
let add (X x) (Y y) = x + y
add (X 1) (Y 2)
这样,参数显示为已命名并保留部分应用程序。
--
编辑
☝ 我不建议创建单例 DU 只是为了模拟命名参数!反之亦然:当我们的域模型中有单例 DU 时,我们知道它们会将其语义用于记录代码并帮助推理代码,在这种情况下或多或少类似于命名参数。
【讨论】:
member _.AddTupled (x: int, y: int) (z: int) = 不能像 .AddTupled (y=2, x=1) 3 那样调用
您必须了解 F# 中的函数调用,这与 C# 等传统命令式语言不同。
let f x y = x + y // defines a function with this signature:
val f : x:int -> y:int -> int
// this function is full or partially applicable:
let g = f 4 // partial application
val g : (int -> int) // a new function that evaluates f 4 y
g 10
val it : int = 14
在传统语言中,函数只有一组参数。在 F# 中,您可以将此类具有多个参数的传统函数表达为具有元组参数的函数:
let f (x, y) = x + y
val f : x:int * y:int -> int
// partial application is no longer possible, since the arguments have been packed into a single tuple
这种传统的元组参数函数不允许使用命名参数调用:
f (x=3, y=5) // interpreted as = test expressions
F# 语言设计在这里是合理的,(x=3, y=5) 没有表达想要的元组。
F# 已经命名参数 已经有一段时间了(这是在过去几年的某个时候添加的)。但是,这仅限于成员函数。一旦你把你的函数翻译成一个成员,它就可以工作了:
type A() =
static member f (x,y) = x + y
A.f(y=3, x=4) // yes, this works!
【讨论】: