Как определить список функций одной и той же 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 ответа:
Проблема заключается в том, что эти функции являются бинарными операторами, т. е. они принимают два операнда и возвращают один. Поэтому вы должны использовать:
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>