开发者

How can I write f(g(h(x))) in Scala with fewer parentheses?

Expressions like

ls map (_ + 1) sum

are lovely because they are left-to-right and not nested. But if the functions in question are defined outside the class, it is less pretty.

Following an example I tried

final class DoublePlus(val self: Double) {
    def hypot(x: Double) = sqrt(self*self + x*x)
}

implicit def doubleToDoublePlus(x: Double) =
    new DoublePlus(x)

which w开发者_如何学Corks fine as far as I can tell, other than

  1. A lot of typing for one method

  2. You need to know in advance that you want to use it this way

Is there a trick that will solve those two problems?


You can call andThen on a function object:

(h andThen g andThen f)(x)

You can't call it on methods directly though, so maybe your h needs to become (h _) to transform the method into a partially applied function. The compiler will translate subsequent method names to functions automatically because the andThen method accepts a Function parameter.

You could also use the pipe operator |> to write something like this:

x |> h |> g |> f


Enriching an existing class/interface with an implicit conversion (which is what you did with doubleToDoublePlus) is all about API design when some classes aren't under your control. I don't recommend to do that lightly just to save a few keystrokes or having a few less parenthesis. So if it's important to be able to type val h = d hypot x, then the extra keystrokes should not be a concern. (there may be object allocations concerns but that's different).

The title and your example also don't match:

f(g(h(x))) can be rewritten asf _ compose g _ compose h _ apply x if your concern is about parenthesis or f compose g compose h apply x if f, g, h are function objects rather than def.

But ls map (_ + 1) sum aren't nested calls as you say, so I'm not sure how that relates to the title. And although it's lovely to use, the library/language designers went through a lot of efforts to make it easy to use and under the hood is not simple (much more complex than your hypot example).


def fgh (n: N) = f(g(h(n))) 
val m = fgh (n) 


Maybe this, observe how a is provided:

def compose[A, B, C](f: B => C, g: A => B): A => C = (a: A) => f(g(a))

basically like the answer above combine the desired functions to a intermediate one which you then can use easily with map.


Starting Scala 2.13, the standard library provides the chaining operation pipe which can be used to convert/pipe a value with a function of interest.

Using multiple pipes we can thus build a pipeline which as mentioned in the title of your question, minimizes the number of parentheses:

import scala.util.chaining._

x pipe h pipe g pipe f
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜