【发布时间】:2011-08-18 11:01:36
【问题描述】:
我想以某种方式组合函数。请在伪代码(不是 F#)中考虑这 2 个函数
F1 = x + y
F2 = F1 * 10 // note I did not specify arguments for F1, 'reverse curry' for lack of a better word
我想让 F# 做的是弄清楚,因为
let F1 x y = x + y
//val F1 : int -> int -> int
代码 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
但是当我添加第二行 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
但现在我还不如使用 C#,我们不再那么遥远了。元组参数破坏了 F# 的许多优雅。此外,我的真实函数 F1 和 F2 的参数远不止 2 个,所以这让我眼花缭乱,这正是我想通过使用 F# 来躲避的。这样说会更自然:
let F1 x y = x + y
let F2 = F1 * 10
有什么方法可以(几乎)做到这一点?
额外积分:这些错误消息到底是怎么回事?为什么第二行let F2 = F1 * 10会改变第一行的打字?
提前感谢您的想法,
格特-简
更新 两种方法(几乎)可以实现所描述的功能。
一个使用元组。第二行看起来有点古怪,工作正常。小缺点是我现在不能使用柯里化,否则我将不得不添加更多古怪的代码。
let F1 (a, b) = a + b
let F2 = F1 >> (*) 10
F2(2, 3) // returns 50
另一种方法是使用记录。乍一看更直接,更容易理解,但需要更多的代码和仪式。确实去掉了 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
【问题讨论】:
-
查看this recent question 的 Haskell 组合。这本质上是同一个问题,但有一些有趣的解决方案可能会在 F# 中实现(我不是母语人士)。
-
嗨,哈马尔,谢谢,Haskell 让我觉得自己有阅读障碍。我想这就是他们对“浓缩汤”的意思。稍后我会试一试,也许所有的 Haskell 看起来确实是一个很好的“心灵健身房”。谢谢!
-
如果
F1取一个元组,那么F2可以拼写为let F2 = F1 >> (*) 10 -
@ildjarn 感谢这个例子,我一开始没有得到元组的方法。我也用这种方法更新了 OP。
标签: f# functional-programming currying higher-order-functions