Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a list of functions of the same arity in Scala?

In the various Lisps, it's possible for me to create a sequence of functions as if they'd just been normal values:

(def ops [+ - * /])

Which I can then iterate through, again, as if they were just normal values:

(doseq [op ops] // (doseq (op ops) is like for (op <- ops) in scala
  (println (op 1 2 3 4)))

Now, I've tried a few things in Scala, all of them failing:

scala> List(+, -, *, /)
<console>:1: error: illegal start of simple expression
       List(+, -, *, /)
             ^

scala> List[Double => Double](+, -, *, /)
<console>:1: error: illegal start of simple expression
       List[Double => Double](+, -, *, /)
                               ^

scala> List[Double => Double](+_, -_, *_, /_)
<console>:8: error: not found: value *
              List[Double => Double](+_, -_, *_, /_)
                                             ^
<console>:8: error: not found: value /
              List[Double => Double](+_, -_, *_, /_)
                                                 ^

So what's the correct procedure of defining a list of functions/operators in Scala?

like image 975
Electric Coffee Avatar asked Oct 04 '14 07:10

Electric Coffee


2 Answers

The problem is that these functions are binary operators, i.e., they take two operands and return one. So you have to use:

List[(Double, Double) => Double](_ + _, _ - _, _ * _, _ / _)
like image 94
bluenote10 Avatar answered Oct 13 '22 17:10

bluenote10


In Scala, most value-level operators are actually unary instance methods (maybe all are, not sure if there are counterexmaples). So when you talk about, say, addition of two values of type Double, you're really referring to a method of the first value that takes the second value as a parameter. The familiar infix operator syntax is just sugar. In other words,

scala> 5.7 + 6.3
res0: Double = 12.0

is really just a nice shorthand for:

scala> 5.7.+(6.3)
res1: Double = 12.0

As @bluenote10 already mentioned, you can capture these operators by creating anonymous function that take both the first instance and its operand as parameters and returns the result of the + method:

scala> (lhs: Double, rhs: Double) => lhs + rhs
res2: (Double, Double) => Double = <function2>

Or as in @bluenote10's example, if the type can be inferred (like in a list with the type provided), you can use the nice underscore syntax:

scala> val doublePlus: (Double, Double) => Double = _ + _
doublePlus: (Double, Double) => Double = <function2>
like image 27
acjay Avatar answered Oct 13 '22 15:10

acjay