【问题标题】:Function composition of methods, functions, and partially applied functions in ScalaScala 中方法、函数和部分应用函数的函数组合
【发布时间】:2011-12-02 18:12:34
【问题描述】:

有点类似于 Stack Overflow 问题 Compose and andThen methods,我一直在研究 Twitter 的 Scala School 教程并很快遇到了评论者遇到的同样问题(这很棒,因为我去了睡觉以为我的问题解决了)。

在教程中,它定义了两个方法:

def addUmm(x: String) = x + " umm"
def addAhem(x: String) = x + " ahem"

而在较新版本的 Scala 中,您不能像这样调用 compose:addUmm(_).compose(addAhem(_)),接受的答案(以及其他一些答案似乎取决于 addUmmaddAhem 的事实是方法,而不是函数,这在尝试调用 compose 时会产生问题。我满意地上床睡觉,成功运行:

scala> ((s: String) => s + " umm").compose((s: String) => s + " ahem")
res0: String => java.lang.String = <function1>

酷。问题是,虽然不能组合方法是有道理的,但当我用我知道的值评估相同的东西时,评估为Function1

val a = (s: String) => s + " umm"
val b = (s: String) => s + " ahem"
val c = a(_).compose(b(_))

嗯,最后一行出现了与原始问题相同的错误,尽管这次它们是函数的部分应用,而不是方法。原始问题中的一个答案(排名靠前,但不是公认的答案)似乎暗示它与如何扩展部分应用程序有关,解释是什么?

对于 Scala 新手来说,无论您是否明确指定 _: String 两个位置,推理器都会得到 a(_).compose(b(_)) 错误,但 a.compose(b) 确实有点令人困惑。

【问题讨论】:

  • 如果使用 lambdas 的下划线快捷方式无法正常工作,请先使用正常语法尝试。下划线的行为经常出乎意料。
  • 您应该在该问题中阅读my answer。我准确地解释了该行的问题所在,它与方法/功能的区别有关。
  • @DanielC.Sobral 你的答案实际上是我引用的答案(排名靠前的那个)(并且很久以前就赞成你的答案:))。我抱怨的那句话似乎是那个问题的核心,所以接受的答案(正如你所指出的那样)似乎是一条红鲱鱼。我只是想在这里考虑一下。

标签: scala function-composition


【解决方案1】:

a(_).compose(b(_)) 扩展为 x =&gt; { a(x).compose(y =&gt; b(y) }。因此错误。你想要的是(x =&gt; a(x)).compose(y =&gt; b(y))。添加一对括号可以解决此问题。

scala> (a(_)).compose(b(_: String))
res56: String => java.lang.String = <function1>

scala> res56("hello")
res57: java.lang.String = helloahemumm

但由于ab 是函数,您可以避免所有这些麻烦,只需执行a compose b

【讨论】:

  • 纯粹从风格上来说,在整个社区中a compose b 是否比a.compose(b) 更受欢迎(还没有阅读任何实际的Scala 项目)?
  • @Marc:是的。就我个人而言,我没有任何硬性规定,但我倾向于仅将前者用于非字母数字方法名称,而将后者用于其他所有内容。
  • @Marc:想象一下你有这行代码:xs filter { f } map { g }。假设在稍后的某个时间点,您需要在末尾添加 toList。你这么说:xs filter { f } map { g } toList。这可能会导致分号推断问题。为避免这些问题,您可以在末尾添加分号,或者添加换行符。这两种选择都是丑陋的IMO。为了避免所有这些废话,我总是喜欢使用xs.filter(f).map(g)。使用这种语法重构总是更容易。
  • @Marc:我的第一条评论中有一个例外:内部 DSL。它们使用空格语法看起来更好,并且通常在设计时小心谨慎,以免在以这种方式编写时引起解析问题。
  • 谢谢!正是我正在寻找的那种洞察力。
【解决方案2】:

您可以简单地使用“a compose b”。

scala> val c = a compose b
c: String => java.lang.String = <function1>

【讨论】:

  • 对,所以我知道我可以,因为这相当于上面的a.compose(b)。与其他案例相比,它更多的是关于“为什么不”。我想我更关心部分组合的内部工作原理(以及,我猜,它的扩展),与另一个问题不同的是,方法和函数的部分组合确实产生了相同的类型。如果这有意义的话。如果这有意义的话。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-03
  • 2011-08-05
  • 2014-03-28
相关资源
最近更新 更多