反向cur ??

gjv*_*amp 7 f# functional-programming currying higher-order-functions

我想以某种方式撰写功能.请考虑伪代码中的这两个函数(不是F#)

F1 = x + y
F2 = F1 * 10 // note I did not specify arguments for F1, 'reverse curry' for lack of a better word
Run Code Online (Sandbox Code Playgroud)

我希望F#做的是弄清楚,因为

let F1 x y = x + y
//val F1 : int -> int -> int
Run Code Online (Sandbox Code Playgroud)

代码let F2 = F1 * 10会给我与F1:相同的签名val F2 : int -> int -> int,并且调用F2 2 3将导致50:(2 + 3)*10.这将是相当聪明的...

发生的事情是完全不同的.第一行符合预期:

let F1 x y = x + y
//val F1 : int -> int -> int
Run Code Online (Sandbox Code Playgroud)

但是当我添加第二行时,let F2 = F1 * 10它会抛出F#.它现在抱怨the type int does not match the type 'a -> 'b -> 'c和F1 requires member ( + ).

我当然可以拼写出来:

let F1(x, y) = x + y
let F2(x, y) = F1(x, y) * 10
Run Code Online (Sandbox Code Playgroud)

但现在我不得不使用C#,我们不再那么遥远了.这些愚蠢的论点打破了F#的优雅.此外,我的真正的函数F1和F2有更多的参数而不仅仅是2,所以这让我变成了眼睛,正是我想用F#躲闪的.这样说会更自然:

let F1 x y = x + y
let F2 = F1 * 10
Run Code Online (Sandbox Code Playgroud)

有什么方法可以(几乎)这样做吗?

额外的积分:这些错误消息究竟发生了什么?为什么第二行会let F2 = F1 * 10改变第一行的输入?

提前感谢您的想法,

格特 - 扬

更新 两个(几乎)执行所描述的工作.

一个使用元组.第二行看起来有点古怪,工作正常.小缺点是我现在不能使用currying或者我必须添加更奇怪的代码.

let F1 (a, b) = a + b
let F2 = F1 >> (*) 10

F2(2, 3) // returns 50
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用记录.这是一个更直接,更容易乍看之下,但需要更多的代码和仪式.删除一些F#的优雅,看起来更像C#.

type Arg (a, b) =
    member this.A = a
    member this.B = b

let F1 (a:Arg) = a.A + a.B
let F2 (a:Arg) = F1(a) * 10

F2 (Arg(2, 3)) // returns 50
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 5

一般来说,没有这种模式.使用larsmans建议的组合器(如curryuncurry)是一种选择,但我认为结果的可读性较低,而且比显式版本更长.

如果经常使用此特定模式,则可以定义一个运算符,用于将函数(带有两个参数)乘以标量:

let ( ** ) f x = fun a b -> (f a b) * x

let F1 x y = x + y
let F2 = F1 ** 10
Run Code Online (Sandbox Code Playgroud)

遗憾的是,您无法将标准数字运算符(*等)的实现添加到现有类型(例如'a -> 'b -> int).但是,这是非常频繁的请求(对其他事情也很有用).或者,您可以将函数包装到一些提供重载数字运算符的对象中(并包含一些Invoke运行该函数的方法).

我认为一个合适的名称将会解除 - 你将*操作符(处理整数)提升到一个函数返回整数的函数.当您使用*可空类型时,它类似于在C#编译器中完成的提升.

解释错误消息 - 它抱怨表达式F1 * 10:

错误FS0001:类型'int'与类型'' - >'b - >'c'不匹配

我认为这意味着编译器正在尝试为*运算符找到实例化.从右侧看,它应该是int这样,因此它认为左侧也应该是int- 但它实际上是两个参数的函数 - 类似于'a -> 'b -> c'.