如何在 F# 或任何函数式语言中柯里化第二个(或第三个、第四个……)参数?
我刚刚开始使用 F#,看看如何使用柯里化将第一个参数预加载到函数中。但是如何使用第二个、第三个或任何其他参数来做到这一点呢?命名参数会让这变得更容易吗?是否有任何其他函数式语言具有命名参数或其他方式使柯里化与参数顺序无关?
I'm just starting up with F# and see how you can use currying to pre-load the 1st parameter to a function. But how would one do it with the 2nd, 3rd, or whatever other parameter? Would named parameters to make this easier? Are there any other functional languages that have named parameters or some other way to make currying indifferent to parameter-order?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
只是为了完整性 - 既然您询问了其他函数语言 - 这就是您在 OCaml(可以说是 F# 的“母亲”)中执行此操作的方式:
因此,在 OCaml 中,您可以硬编码您想要的任何命名参数,只需使用其名称 (<上例中的 code>y)。
正如您所发现的那样,微软选择不实现此功能...以我的拙见,这与“与语言设计的其他方面的交互不良”无关...更有可能是因为这需要额外的努力(在语言实现中)以及它将导致语言走向世界的延迟 - 事实上只有很少人会(a)意识到 OCaml 的“降级”,(b)无论如何使用命名函数参数。
我是少数,并且确实使用它们 - 但它确实可以通过本地函数绑定在 F# 中轻松模拟:
Just for completeness - and since you asked about other functional languages - this is how you would do it in OCaml, arguably the "mother" of F#:
So in OCaml you can hardcode any named parameter you want, just by using its name (
y
in the example above).Microsoft chose not to implement this feature, as you found out... In my humble opinion, it's not about "poor interaction with other aspects of the language design"... it is more likely because of the additional effort this would require (in the language implementation) and the delay it would cause in bringing the language to the world - when in fact only few people would (a) be aware of the "stepdown" from OCaml, (b) use named function arguments anyway.
I am in the minority, and do use them - but it is indeed something easily emulated in F# with a local function binding:
在 Python 中,您可以使用 functools.partial 或 lambda。 Python 有命名参数。
functools.partial 可用于指定第一个位置参数以及任何命名参数。
In Python, you can use
functools.partial
, or a lambda. Python has named arguments.functools.partial
can be used to specify the first positional arguments as well as any named argument.可以在不声明任何内容的情况下执行此操作,但我同意 Brian 的观点 lambda 或自定义函数可能是更好的解决方案。
我发现我最常需要这个来部分应用除法或减法。
概括来说,我们可以声明一个函数
applySecond
:为了遵循逻辑,这样定义函数可能会有所帮助:
现在
f
是来自'a< 的函数/code> 到
'b -> 'c
.它由ff
组成,它是来自'b ->; 的函数。 'c
到'c
,这是arg2
部分应用到前向管道运算符的结果。此函数将为arg2
传递的特定'b
值应用于其参数。因此,当我们将f
与ff
组合时,我们会得到一个从'a
到'c
的函数,该函数使用给定的'b
参数的值,这正是我们想要的。将上面的第一个示例与以下示例进行比较:
同时比较这些:
或者,比较:
lambda 版本似乎更容易阅读。
It's possible to do this without declaring anything, but I agree with Brian that a lambda or a custom function is probably a better solution.
I find that I most frequently want this for partial application of division or subtraction.
To generalize, we can declare a function
applySecond
:To follow the logic, it might help to define the function thus:
Now
f
is a function from'a
to'b -> 'c
. This is composed withff
, a function from'b -> 'c
to'c
that results from the partial application ofarg2
to the forward pipeline operator. This function applies the specific'b
value passed forarg2
to its argument. So when we composef
withff
, we get a function from'a
to'c
that uses the given value for the'b
argument, which is just what we wanted.Compare the first example above to the following:
Also compare these:
Alternatively, compare:
The lambda versions seem to be easier to read.
通常你只使用 lambda:
是一个类似 'f' 的函数,但第三个参数绑定到 42。
你也可以使用组合器(就像有人在评论中提到 Haskell 的“flip”),它重新排序参数,但我有时发现令人困惑。
请注意,大多数柯里化函数都是这样编写的,即最有可能部分应用的参数排在第一位。
F# 为方法提供了命名参数(不是 let 绑定的函数值),但这些名称适用于“元组”参数。命名的柯里化参数没有多大意义;如果我有一个双参数柯里化函数“f”,我希望给定
“g”或“h”可以替代“f”,但“命名”参数使得这不一定成立。也就是说,“命名参数”与语言设计的其他方面的交互效果很差,而且我个人不知道有什么好的设计可以让“命名参数”与“第一类柯里化函数值”交互良好。
Typically you just use a lambda:
is a function like 'f' but with the third parameter bound to 42.
You can also use combinators (like someone mentioned Haskell's "flip" in a comment), which reorder arguments, but I sometimes find that confusing.
Note that most curried functions are written so that the argument-most-likely-to-be-partially-applied comes first.
F# has named parameters for methods (not let-bound function values), but the names apply to 'tupled' parameters. Named curried parameters do not make much sense; if I have a two-argument curried function 'f', I would expect that given
then 'g' or 'h' would be substitutable for 'f', but 'named' parameters make this not necessarily true. That is to say, 'named parameters' can interact poorly with other aspects of the language design, and I personally don't know of a good design offhand for 'named parameters' that interacts well with 'first class curried function values'.
F# 所基于的语言 OCaml 具有可以按任何顺序指定的标记(和可选)参数,并且您可以根据这些参数名称部分应用函数。我不相信 F# 有这个功能。
您可以尝试创建类似 Haskell 的
flip
函数的东西。创建使参数在参数列表中进一步跳转的变体应该不会太难。OCaml, the language that F# was based on, has labeled (and optional) arguments that can be specified in any order, and you can partially apply a function based on those arguments' names. I don't believe F# has this feature.
You might try creating something like Haskell's
flip
function. Creating variants that jump the argument further in the argument list shouldn't be too hard.