Компоновка и методы andThen
Я следую учебному руководству Соответствие шаблонов и функциональная композиция в Scala compose
и andThen
. Вот такой пример:
scala> def addUmm(x: String) = x + " umm"
scala> def addAhem(x: String) = x + " ahem"
val ummThenAhem = addAhem(_).compose(addUmm(_))
Когда я пытаюсь его использовать, я получаю сообщение об ошибке:
<console>:7: error: missing parameter type for expanded function ((x$1) => addAhem(x$1).compose(((x$2) => addUmm(x$2))))
val ummThenAhem = addAhem(_).compose(addUmm(_))
^
<console>:7: error: missing parameter type for expanded function ((x$2) => addUmm(x$2))
val ummThenAhem = addAhem(_).compose(addUmm(_))
^
<console>:7: error: type mismatch;
found : java.lang.String
required: Int
val ummThenAhem = addAhem(_).compose(addUmm(_))
Однако это работает:
val ummThenAhem = addAhem _ compose addUmm _
или даже
val ummThenAhem = addAhem _ compose addUmm
Что не так с кодом в учебнике? Разве последнее выражение не совпадает с первым без круглых скобок?
Ответы
Ответ 1
addAhem
- метод. Метод compose
определяется функциями. addAhem _
преобразует addAhem
из метода в функцию, поэтому compose
можно вызвать на нем. compose
ожидает функцию как аргумент. Вы даете ему метод addUmm
, преобразовывая addUmm
в функцию с addUmm _
(подчеркивание может быть опущено, потому что компилятор может автоматически преобразовать метод в функцию, когда он знает, что функция ожидается в любом случае). Итак, ваш код:
addAhem _ compose addUmm
совпадает с
(addAhem _).compose(addUmm)
но не
addAhem(_).compose(addUmm(_))
PS
Я не смотрел ссылку, которую вы предоставили.
Ответ 2
Ну, это:
addUhum _
- это расширение. Он преобразует методы в функции. С другой стороны, это:
addUhum(_)
- анонимная функция. Фактически, это приложение частичной функции, поскольку этот параметр не применяется, а вся вещь преобразуется в функцию. Он расширяется до:
x => addUhum(x)
Точные правила для расширения немного сложно объяснить, но, в основном, функция "начнет" в самом внутреннем разделителе выражений. Исключение составляют приложения с частичной функцией, где "x" перемещается за пределы функции - если вместо параметра используется _
.
В любом случае, так оно расширяется:
val ummThenAhem = x => addAhem(x).compose(y => addUmm(y))
Увы, тип inferencer не знает тип x или y. Если вы хотите, вы можете точно увидеть, что он попробовал, используя параметр -Ytyper-debug
.
Ответ 3
Из compose
документации:
Составляет два экземпляра Function1 в новом Function1, с этим функция применяется последним.
поэтому вы должны написать
scala> val ummThenAhem = (addAhem _).compose(addUmm _)
ummThenAhem: String => java.lang.String = <function1>
рассматривать addAhem
и addUmm
как частично применяемые функции (т.е. function1
)
scala> addAhem _
res0: String => java.lang.String = <function1>
Ответ 4
Я считаю, что учебник был написан для более ранней версии Scala (возможно, 2.7.7 или ранее). С тех пор произошли некоторые изменения в компиляторе, а именно расширения для системы типов, которые теперь приводят к отказу типа inferencing:
addUhum(_).compose(addAhem(_))
Подъем к функции по-прежнему работает с этим синтаксисом, если вы просто пишете:
addUhum(_)