Best practice: applying multiple transformations using fold

Hello everyone, I’ve been thinking about this problem where I have an arbitrary payload, for simplicity lets say its a string, and I want to run multiple transformations on it, returning the transformed string in the end. Is there a way for me to store each of the transformation functions in a list, and then fold this list over the initial string? I’ve been playing around with an example today and it seems like it should be possible but I’m stuck on the actual fold. Is there a cleaner way of doing this? Would it make more sense to represent this type of computation using a monoid/semigroup? Any insight here is greatly appreciated.

val func1 = (s: String) => s + " func1"
val func2 = (s: String) => s + " func2"
val procList = List(func1, func2)

val s = "beginning string"

procList.fold(s) { ... } // Actual folding logic

You need a foldLeft because you want to ensure the order in which the operations are applied and you want to change the output type.

functions.foldLeft(s) {
  case (acc, f) =>
    f(acc)
}

Other approaches include reducing the list of functions into a single one using andThen or chain

functions.reduce(_ andThen _)(s)

Function.chain(functions)(s)
6 Likes

It makes some sense, not sure about the “more”. Functions A => A form a monoid. With standard composition, it’s right-binding, though.

def mempty[A]: A => A = a => a
def mplus[A](a: A => A, b : A => A): A => A = a.compose(b)
procList.fold(mempty)(mplus)(s)
// => "beginning string func2 func1"

…or, shorter…

procList.fold(identity[String] _)(_.compose(_))(s)

In cats:

procList.combineAll(MonoidK[Endo].algebra)(s)
2 Likes