Writing function parameters before function to be

2019-09-13 14:01发布

问题:

Is it possible to have syntax like (parameter1, parameter2) applied myFunction. Here myFunction would be applied to the given parameters. Concrete example: val myFunction = (a:String) => a+a+"there"; "hello" applied myFunction should output "hellohellothere". I know it's possible to do (parameter1, parameter2) match {case myFunctionWrittenOut}, so the above would become "hello" match {case a:String => a+a+"there"} but here you have to write out the function: you can't use a reference.

回答1:

I don't think it's possible with standard scala. But you can write some helper methods that would make something like this available:

implicit class Applied1[T](val t: T) extends AnyVal {
  def applied[R](f: T => R): R = f(t)
}

implicit class Applied2[T1, T2](val t: (T1, T2)) extends AnyVal {
  def applied[R](f: (T1, T2) => R): R = f(t._1, t._2)
}

implicit class Applied3[T1, T2, T3](val t: (T1, T2, T3)) extends AnyVal {
  def applied[R](f: (T1, T2, T3) => R): R = f(t._1, t._2, t._3)
}

// ... and 19 more implicit classes: Applied4 to Applied22

And then you can use it like this:

def minus(a: Int): Int = -a
def plus(a: Int, b: Int): Int = a + b
def plus(a: Int, b: Int, c: Int): Int = a + b + c

scala> 5 applied minus
res0: Int = -5

scala> (1, 2) applied plus
res1: Int = 3

scala> (1, 2, 3) applied plus
res2: Int = 6

But this may be a bit more complex to use with generic functions, or functions with implicit arguments:

def mul[T : Numeric](a: T, b: T): T = {
  import Numeric.Implicits._
  a * b
}

scala> (1.5, 2.5) applied (mul(_, _))
res3: Double = 3.75


回答2:

Implicit classes can be used to achieve something which which seems to be similar to what you are looking for.

An implicit class with only one constructor argument can be used as a pattern to add methods to the a given type. One example is DurationInt which "adds" methods to integers to enable converting them to durations. It is imported into scope using import scala.concurrent.duration._

A simplified version of DurationInt could be defined as follows:

implicit class DurationInt(n: Int) {
  def seconds: FiniteDuration = Duration(n, TimeUnit.SECONDS)
}

This enables use of the seconds method on all integers

2.seconds // Returns a duration object

For functions with multiple arguments you can use a tuple argument for the implicit class:

implicit class TupleConcat(tuple: (String, String)) {
  def concat: String = tuple._1 + tuple._2
}

// enables the following syntax
("aa", "bb").concat

It is common for implicit classes such as these to extend AnyVal, this allows some compiler optimizations which avoid actually having to instantiate the implicit class in many cases.

implicit final class DurationInt(val n: Int) extends AnyVal { /* implementation */ }


回答3:

In Scala, the parameter list of a function is always written before the function:

val fn = (a: Int, b: Int) => a + b
//       ^  parameters  ^    ^ function