Scott Frazer
Scott Frazer

Reputation: 2185

How do I chain calls that take blocks as inputs?

Say I have these declarations:

val f1 = EventFilter.info(pattern = s"starting calls: three_step.ps, three_step.ps2, three_step.ps3", occurrences = 1)
val f2 = EventFilter.info(pattern = s"starting calls: three_step.cgrep, three_step.wc", occurrences = 1)
val f = Seq(f1, f2)

Right now I can do this:

f1.intercept { f2.intercept {
  ... Some code here ...
}}

However, I want that first line to be expressed as a function of val f = Seq(f1, f2) rather than of f1 and f2 directly. I'm not sure how to express this but I want to be able to do this for any Seq[EventFilter] objects

Upvotes: 0

Views: 59

Answers (2)

Daenyth
Daenyth

Reputation: 37461

This should work in scalaz:

implicit def endofunctionMonoid[A] = new Monoi[Function1[A, A]] {
  def append(f1: Function1[A, A], f2: => Function1[A, A]): Function1[A, A] =
    f1 _ compose f2 _
  def zero: Function1[A, A] = a => a
}
val fs = List(f1, f2) // event filters
fs.foldMap { _.intercept _ } // map the list to Function1s and accumulate via the semigroup operation.

Upvotes: 1

Ben Reich
Ben Reich

Reputation: 16324

I'm assuming that intercept takes in and returns the same type here, since that's the only way to chain functions in this way.

Most generally, you can use a foldLeft or foldRight to accomplish this sort of chaining.

eventFilters.foldLeft(startingValue) { 
    case (acc, next) => next.intercept(acc) 
}

You might also be interested in Future.chain[T], which chains together a sequence of functions T => T. If you would want to use that, you need to make your Seq[EventFilter] into a Seq[Foo => Foo] (where Foo is the parameter/return type of intercept):

val interceptFuncs = eventFilters.map(_.intercept _) //Seq[Foo => Foo]
Function.chain(interceptFuncs)(startingValue)

Upvotes: 1

Related Questions