LordTwaroog
LordTwaroog

Reputation: 1738

Chaining function calls in scala (or equivalent of Ruby's yield_self)

What is an idiomatic way of chaining function calls, passing results between each with parameters supplied on the way in Scala?

Here's an example:

def a(x : A, param : String) : A = x
def b(x : A, param : String) : A = x
def c(x : A, param : String) : A = x
def d(x : A, param : String, anotherParam : String) : A = x

val start = A()

d(c(b(a(start, "par1"), "par2"), "par3"), "par4", "anotherPar")

One approach that comes to my mind is Ruby's Kernel#yield_self which allows to do the following:

start
  .yield_self {|x| a(x, "par1") }
  .yield_self {|x| b(x, "par2") } 
  .yield_self {|x| c(x, "par3") } 
  .yield_self {|x| d(x, "par4", "anotherPar) } 

Upvotes: 3

Views: 2156

Answers (2)

Andrey Tyukin
Andrey Tyukin

Reputation: 44957

I'd say that chaining functions using well... chaining isn't that bad already:

(
  { (x: A) => a(x, "par1") } andThen 
  { x => b(x, "par2") } andThen 
  { x => c(x, "par3") } andThen 
  { x => d(x, "par4", "anotherPar") }
)(start)

However, if you insist on having a yieldSelf method, here you go:

import scala.language.implicitConversions

case class YieldSelf[X](x: X) {
  def yieldSelf[Y](f: X => Y): Y = f(x)
}
implicit def everythingCanYieldSelf[X](x: X) = YieldSelf(x)

start.
  yieldSelf{ a(_, "par1") }.
  yieldSelf{ b(_, "par2") }.
  yieldSelf{ c(_, "par3") }.
  yieldSelf{ d(_, "par4", "anotherPar") }

As soon as the implicit definition is in the scope, it adds a yieldSelf method to every object, which has the same semantics as in Ruby.

Upvotes: 3

Sergii Lagutin
Sergii Lagutin

Reputation: 10681

You may combine chain of functions into one function:

val start = new A()

val func: (A => A) =
  ((x: A) => a(x, "par1"))
    .andThen(b(_, "par2"))
    .andThen(c(_, "par3"))
    .andThen(d(_, "par4", "anotherPar"))

func(start)

But I'm not sure if it's a your goal.

Upvotes: 3

Related Questions