【问题标题】:Concise syntax for function composition in Scala?Scala中函数组合的简洁语法?
【发布时间】:2014-03-14 15:58:48
【问题描述】:

我正在学习 Scala 并遇到了以下任务 - 如果字符串为空则返回 null,否则将其大写。

Apache Commons 中有两个函数组合在一起解决了这个问题。在 Haskell 我只想写:

upperCaseOrNull = StringUtils.stripToNull . StringUtils.upperCase

但是我找不到在 Scala 中进行简单而干净的函数组合的方法。我找到的最短方法如下:

def upperCaseOrNull (string:String) = StringUtils.stripToNull (StringUtils.upperCase(string))
def upperCaseOrNull = StringUtils.stripToNull _ compose StringUtils.upperCase _

Scala 是否提供更简洁的语法,可能没有所有这些下划线?

【问题讨论】:

  • def upperCaseOrNull (string:String) = if (string == "") null else string.toUpperCase

标签: scala higher-order-functions function-composition


【解决方案1】:

Haskell 在它真正关心的一些事情上是极其紧凑的大师。所以几乎不可能被击败。如果你做的函数组合太多以至于开销真的妨碍了你(就我个人而言,重复StringUtils.!我会更麻烦),你可以做类似的事情

implicit class JoinFunctionsCompactly[B,C](g: B => C) {
  def o[A](f: A => B) = g compose f
}

所以现在你在 Haskell 上只有四个额外的字符(_ 两次)。

【讨论】:

  • 我不同意这是一个 haskell 功能。组合函数是所有函数式语言的基本特征。在球拍中:(define trim-upercase (compose string-trim string-upcase))。如果我们必须传递参数或其替代项(下划线),那么它似乎是一个不必要的函数包装:amara.org/pl/videos/I7DUcht5Am5L/info/…
  • @piotrek - 如果您将函数定义为函数(即val upperCase = (s: String) => ...),则不需要_。此外,如果总体上大致如此紧凑,谁会在意几个下划线?在这里,Racket 并不比 Scala 更紧凑。 Racket 的开销是 (define (compose )),而 Scala 的开销是 def = _ compose _。如果您只是说“我不喜欢下划线的外观”,请定义一个 compose 方法和compose(g,f)
  • 编写g.h使用JoinFunctionsCompactly(g).o(h)和编写f.g.hJoinFunctionsCompactly(f).o(JoinFunctionsCompactly(g).o(h))
  • @AJarofClay - 你可以,但这不是代码的重点。您可以使用g o hf o g o h
  • @RexKerr 你是对的,虽然它应该是g _ o hf _ o g o h
【解决方案2】:

如果涉及null,我不会声称任务很简单。如果 Scala 中的 None 可以,你为什么需要 null?我认为由于 null 被返回,该函数对撰写不是很友好。

一旦您将StringUtils.stripToNull 转换为为nullSome 返回None,否则,您可以使用scala.Option.map 并使用_.toUpperCase 执行它 - 请参阅scala.Option 的scaladoc讨论了具体的例子。

也有人建议如下:

scala> def upperCaseOrNone = (s: String) => Option(s).fold(s) { _.toUpperCase }
upperCaseOrNone: String => String

【讨论】:

  • 如果None 可用,为什么我需要null?因为在 hql 查询中我不能使用 None
  • 此外,我相信null 在这里无关紧要。我想组合两个现有函数,而不是将它们包装在 Option 中或定义新的 lambda
【解决方案3】:

可以让构图稍微紧凑一些:

使用andThen

将其简化为一个下划线(即使组合了两个以上的函数):

def upperCaseOrNull = StringUtils.upperCase _ andThen StringUtils.stripToNull

具有三个功能的更一般情况:

def fgh  = h _ andThen g andThen f

使用辅助函数

如果fgh 是接受一个String 参数并返回一个String 的函数:

def fgh = composeMany[String](f, g, h)

composeMany 函数如下所示:

def composeManyHelper[T](composed: T => T, funcs: Seq[T => T]): T => T = {
  if (funcs.isEmpty) {
    composed
  } else {
    composeManyHelper[T](funcs.head compose composed, funcs.tail)
  }
}

// Take zero or more functions that take a param of type T and return a value of type T,
// and return a function that is the composition of all the functions
def composeMany[T](funcs: (T => T)*): T => T = {
  composeManyHelper[T](identity[T], funcs.reverse)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-24
    • 1970-01-01
    相关资源
    最近更新 更多