【问题标题】:Splitting a tuple inline as parameters to a function with non-tuple arguments将元组内联作为参数拆分为具有非元组参数的函数
【发布时间】:2013-06-07 20:22:07
【问题描述】:

我有一个带有两个参数的函数,例如:

let f a b = a = b

然后我有第二个函数返回一个元组:

let g = (a, b)

我想将元组中的 a 和 b 作为参数从 g 传递给 f 一行。我可以在两个语句中执行此操作,但我想这样做的原因是我的调用函数执行 or 并且我宁愿不调用 f 除非第一种情况为 false,以节省不必要的处理。

let calling =
  someboolean || 
  f g // want to split result of g to parameters for f without calling g twice

关于如何做到这一点的任何提示?我知道我可以让 f 取一个元组,但我想保留柯里化的选项。

我希望我解释得足够好。 :)

【问题讨论】:

  • Here's 一个很好的、有组织的 F# 符号和运算符的参考列表,如果您需要有关其他答案的更多信息
  • 如果可以的话,我会标记几个答案,但我选择了我认为对特定问题最优雅的解决方案。也就是说,我认为 Thomas 关于重构 f 和 g 调用的建议可能是最“正确”的。谢谢大家!

标签: f#


【解决方案1】:

你也可以这样做:

let calling = someBoolean || g ||> f

因为:

(||>) : ('a * 'b -> ('a -> 'b -> 'c) -> 'c)

(同样(|||>) : ('a * 'b * 'c -> ('a -> 'b -> 'c -> 'd) -> 'd)

【讨论】:

  • 还有(<||)(<|||)
【解决方案2】:

您可以定义一个函数,将一个柯里化函数转换为一个接受一对参数的函数:

uncurry f (a, b) = f a b

let calling = someBoolean || (uncurry f) g

【讨论】:

    【解决方案3】:

    您可以从内联元组中提取,仍然可以从短路中受益。

    let calling = someBoolean || let a,b = g in f a b
    

    【讨论】:

      【解决方案4】:

      如前所述,您可以定义 uncurry 组合器将采用两个参数的函数转换为采用元组的函数。

      但是我建议不要这样做 - 这种编程风格在 F# 中并不是真正惯用的(例如,在 Haskell 中),而且我认为它使代码难以阅读、调试和维护。

      那么,该怎么做呢?

      • 如果这两个值在逻辑上属于一起(表示代码中其他地方使用的某个实体),则更改 f 以获取一个元组。

      • 如果它们只是两个值,则使用let 和模式匹配来分解元组。这会更长,但您必须为组件命名,这将提高可读性。

      在您的示例中,g 实际上是一个值,因此您可以只写:

      let someThing, otherThing = g
      boolThing || (f someThing otherThing)
      

      【讨论】:

      • 我认为这是@TomasPetricek 的最佳答案。将元组分解为两个值可能最容易阅读,并且就 F# 习语而言也是最“正确”的。
      • 是的,我不这样做的主要原因是为了保持“或”的短路。在实际代码中,g 中有一些枚举和潜在的数据库访问,所以如果条件的第一部分评估为 true,我不想点击该代码。
      • @McMuttons 听起来您想使用 F# 出色的 Lazy<_> 类型和 lazy ... 表达式。
      • @McMuttons 是的,我认为短路是提出这个问题的一个很好的理由。我的建议是将正确的分支重构为一个单独的函数,然后调用它(为了便于阅读,另外,你可以在 F# 中使用嵌套函数!)
      猜你喜欢
      • 2019-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-11
      相关资源
      最近更新 更多