F# 部分应用第二个参数

5

在F#中,如果我使用一个需要两个参数的函数,例如mod (%):

13 % 10
// val it : int = 3

这与

相同。
(%) 13 10
// val it : int = 3

有没有办法使用管道符号编写它,将13进行柯里化?

显然,“两个参数的函数”实际上是一个返回中间函数的一参数函数。因此,可以使用管道。

10 |> (%) 13
// val it : int = 3

然而,我需要相反的方式,即将第一个参数13传递,第二个参数10部分应用,但不是第一个参数。

是否有任何语言可以帮助实现这一点,而无需每次创建额外的lambda,即避免以下情况?

13 |> (fun x -> x % 10)

1
请参见 https://dev59.com/J3I-5IYBdhLWcg3wVWti。 - Mankarse
没错,但是有没有办法在不每次创建额外函数的情况下反转部分应用的顺序,即不使用let mod10,也不使用(fun x -> x % 10)? - Ilya Kharlamov
1
这可能只是一个打字错误(在多个地方),但我仍然想指出 (%) 10 13 = 10。因此,参数的顺序在前缀和中缀形式之间不会改变。 - sebhofer
4个回答

7

没有内置的、标准的方法来完成这个任务。此外,由于函数应用的工作原理,这是不可能的:一旦您写下(%) 13,您已经应用了第一个参数,因为在F#中,函数应用具有最高且不可配置的优先级。

当然,您可以自己编写一个特殊的函数来生成一个“奇怪”的函数应用——它将应用第二个参数并留下第一个参数的空位:

let ap f x = fun y -> f y x

接下来:

let x = 13 |> ap (%) 10
> x : int = 3

顺带提一下,函数ap在ML语言中是半标准的出现,通常被称为flip,因为它的作用是“翻转”参数的顺序:

let flip f x y = f y x

或者,你甚至可以将它制作成一个运算符:
let (-*-) = flip

然后:
let x = 13 |> (%) -*- 10
> x : int = 3

然而,这种技巧很快就会变得难以阅读。实际上,更好的做法是声明一个函数来完成你需要的操作:

let mod10 x = x % 10

然后:

let x = 13 |> mod10

或者,如果你真的需要它非常通用:
let mod' x y = y % x

然后:
let x = 13 |> mod' 10

4
你可以编写一个组合器来处理任何双参数函数的操作:

例如:

let inline flip f y x = f x y

这可以被用作:

13 |> flip (%) 10

2

F#中已经包含了一个运算符,可以实现你想要的功能,即<|

10 |> (%) <| 13;;
val it : int = 10

这相当于
(10 |> (%)) 13;;
val it : int = 10

很接近,但不完全符合要求。[11;12;13] |> Seq.map ((%) <| 10);; 预期结果:[1;2;3] 实际结果:[10;10;10] - Ilya Kharlamov

1

K,你正在寻找一个翻转效果

let flip f a b = f b a

让 mod10 x = x % 10 和 (fun x -> x % 10) 差不多,不是吗? - Ilya Kharlamov
1
是的,您是在询问翻转运算符、身份函数或类似的内容吗?http://techneilogy.blogspot.com/2010/06/flip-operator-for-f.html - Terrance
谢谢提供链接,就是这个,没错,“flip”。 - Ilya Kharlamov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接