简体   繁体   中英

Scala: Fold over a list of operations with varied signatures?

I want to write a set of classes that each implement a particular operation, so they take an argument of some type and return something of the same type or a different type. Then, given a list of these operations, fold over an initial value, applying each operation in turn, and supplying the result to the next operation in the list.

For instance, something like this:

val program = List[Operation](Add3, ToString, Repeat5)
program.foldLeft(5) ((progress, operation) => operation.apply(progress))

So the first operation adds 3, the second turns it into a string, and the last repeats that string 5 times. This would result in:

"88888"

How do I go about implementing this kind of thing in Scala?

Thanks!

Putting methods of differing signatures in a List would be difficult to do in a type-safe way, but you can line them up in a different manner.

def add3(i: Int): Float = i + 3.1f
def num2string(f: Float): String = f"$f%.1f"
def repeat5(s: String): String = s * 5

val all = add3 _ andThen num2string andThen repeat5

all(6)  // res0: String = 9.19.19.19.19.1

Note that the compiler won't let you put these methods in the wrong order. That's a nice feature you won't get using a List of ops.


A chain of andThen operations can be built dynamically, at run time, more or less the same as you would to build a List .

Start with the argument type. (In your example, Int .)

val ops0: Int => Int = identity _

Now you have an Int => Int function and you can add ops, or not, depending on the current conditions. The type will always be Int => ?? where ?? is the return type of the last op added to the chain.

You can do something like this.Var is discouraged ,but at this time time this is the best I came up with

abstract class Operation
  case class Add3() extends Operation with Function[Int, Int] {
    def apply(x: Int) = x + 3
  }

  case class ToString() extends Operation with Function[Int, String] {
    def apply(x: Int) = x.toString
  }

  case class Repeat5() extends Operation with Function[String, String] {
    def apply(s: String) = s * 5
  }

  val lst = List[Operation](Add3(), ToString(), Repeat5())
  var v = "5"
  lst.foreach { op =>
    {
      v = op match {
        case op: Add3     => op.apply(v.toInt).toString
        case op: ToString => op.apply(v.toInt)
        case op: Repeat5  => op.apply(v)
      }
    }
  }

  println(v)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM