问题
I'm learning Scala and ran across the following task - if string is blank then return null, otherwise uppercase it.
There are two functions in Apache Commons that composed together solves the problem. In Haskell I'd just write:
upperCaseOrNull = StringUtils.stripToNull . StringUtils.upperCase
However I can't find a way to do an easy and clean function composition in Scala. the shortest way I found is as follows:
def upperCaseOrNull (string:String) = StringUtils.stripToNull (StringUtils.upperCase(string))
def upperCaseOrNull = StringUtils.stripToNull _ compose StringUtils.upperCase _
Does Scala offer a more concise syntax, possibly without all those underscores?
回答1:
Haskell is a master of extreme compactness for a few things it really cares about. So it's pretty much impossible to beat. If you are doing so much function composition that the overhead really gets in your way (personally, I'd be a lot more troubled by repeating StringUtils.
!), you can do something like
implicit class JoinFunctionsCompactly[B,C](g: B => C) {
def o[A](f: A => B) = g compose f
}
so now you only have four extra characters (_
twice) over Haskell.
回答2:
I wouldn't claim a task be simple if null
's are involved. Why would you need null
if None
in Scala would do? I think that due to null
being returned the function is not very compose-friendly.
Once you transform StringUtils.stripToNull
to return None
for null
and Some
otherwise, you could then use scala.Option.map and execute it with _.toUpperCase
- see the scaladoc for scala.Option where this particular example is discussed.
One might also suggest something as follows:
scala> def upperCaseOrNone = (s: String) => Option(s).fold(s) { _.toUpperCase }
upperCaseOrNone: String => String
回答3:
It is possible to make composition slightly more compact:
Using andThen
To get it down to a single underscore (even with more than two functions composed):
def upperCaseOrNull = StringUtils.upperCase _ andThen StringUtils.stripToNull
More general case with three functions:
def fgh = h _ andThen g andThen f
Using a helper function
If f
, g
and h
are functions taking one String
parameter and returning a String
:
def fgh = composeMany[String](f, g, h)
Where the composeMany
function looks like this:
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)
}
来源:https://stackoverflow.com/questions/22410045/concise-syntax-for-function-composition-in-scala