【问题标题】:F# Partially apply the second argumentF# 部分应用第二个参数
【发布时间】:2019-01-14 18:24:24
【问题描述】:

在 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)

【问题讨论】:

  • 对,但是有什么办法可以颠倒部分应用的顺序,而不需要每次都创建额外的函数,即不用 let mod10,不用 (fun x -> x % 10)
  • 这可能只是一个错字(嗯,不止一个地方),但我仍然想指出(%) 10 13 = 10。所以参数的顺序不会在前缀和中缀形式之间改变。

标签: f# functional-programming currying partial-application


【解决方案1】:

F# 已经包含一个可以做你想做的事情的操作符,即<|:

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

这相当于

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

【讨论】:

  • 很接近,但不完全是需要的 [11;12;13] |> Seq.map ((%)
【解决方案2】:

没有内置的标准方法可以做到这一点。此外,由于函数应用的工作方式,不可能这样做:只要你写了(%) 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

【讨论】:

    【解决方案3】:

    K,你正在寻找翻转

    let flip f a b = f b a
    

    【讨论】:

    【解决方案4】:

    您可以编写一个组合器,对任何有两个参数的函数执行此操作:

    let inline flip f y x = f x y
    

    这可以用作:

    13 |> flip (%) 10
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-07
      • 1970-01-01
      相关资源
      最近更新 更多