Как определить список функций одной и той же arity в Scala?


В различных Лиспах я могу создать последовательность функций, как если бы они были просто нормальными значениями:

(def ops [+ - * /])

Которые я затем могу повторить снова, как если бы они были просто нормальными значениями:

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

Итак, я попробовал несколько вещей в Scala, и все они потерпели неудачу:

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](+_, -_, *_, /_)
                                                 ^

Итак, какова правильная процедура определения списка функций / операторов в Scala?

2 6

2 ответа:

Проблема заключается в том, что эти функции являются бинарными операторами, т. е. они принимают два операнда и возвращают один. Поэтому вы должны использовать:

List[(Double, Double) => Double](_ + _, _ - _, _ * _, _ / _)

В Scala большинство операторов уровня значений на самом деле являются унарными методами экземпляра (возможно, все они, не уверен, есть ли контрпримеры). Поэтому, когда вы говорите, скажем, о сложении двух значений типа Double, Вы на самом деле имеете в виду метод первого значения, который принимает второе значение в качестве параметра. Знакомый синтаксис оператора инфикса - это просто сахар. Другими словами,

scala> 5.7 + 6.3
res0: Double = 12.0

На самом деле просто хорошее сокращение для:

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

Как @bluenote10 уже упомянутые , вы можете захватить эти операторы, создав анонимную функцию, которая принимает как первый экземпляр, так и его операнд в качестве параметров и возвращает результат метода +:

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

Или, как в Примере @bluenote10, если тип может быть выведен (например, в списке с указанным типом), вы можете использовать приятный синтаксис подчеркивания:

scala> val doublePlus: (Double, Double) => Double = _ + _
doublePlus: (Double, Double) => Double = <function2>