Составь и потом методы
Я следую инструкциям по сопоставлению шаблонов и функциональной композиции в 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
Что не так с кодом в учебнике? Разве последнее выражение не совпадает с первым без скобок?
4 ответа
addAhem
это метод. compose
Метод определяется по функциям. addAhem _
новообращенные addAhem
от метода к функции, так compose
можно вызвать на это. compose
ожидает функцию в качестве аргумента. Вы даете ему метод addUmm
путем преобразования addUmm
в функцию с addUmm _
(Подчеркивание может быть опущено, потому что компилятор может автоматически преобразовывать метод в функцию, когда он знает, что функция все равно ожидается). Итак, ваш код:
addAhem _ compose addUmm
такой же как
(addAhem _).compose(addUmm)
но нет
addAhem(_).compose(addUmm(_))
PS Я не смотрел на ссылку, которую вы предоставили.
Ну, это:
addUhum _
это расширение eta. Преобразует методы в функции. С другой стороны, это:
addUhum(_)
это анонимная функция Фактически, это частичное применение функции, в котором этот параметр не применяется, и все это преобразуется в функцию. Расширяется до:
x => addUhum(x)
Точные правила для раскрытия немного сложно объяснить, но, в основном, функция "запустится" в самом внутреннем разделителе выражения. Исключение составляют частичные функции приложения, где "х" перемещается за пределы функции - если _
используется вместо параметра.
Во всяком случае, вот как это расширяется:
val ummThenAhem = x => addAhem(x).compose(y => addUmm(y))
Увы, механизм вывода типов не знает тип x или y. Если вы хотите, вы можете увидеть, что именно он пытался с помощью параметра -Ytyper-debug
,
От 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>
Я считаю, что руководство было написано для более ранней версии Scala (вероятно, 2.7.7 или более ранней). С тех пор в компиляторе произошли некоторые изменения, а именно расширения системы типов, которые теперь приводят к сбою вывода типа в:
addUhum(_).compose(addAhem(_))
Поднятие функции все еще работает с этим синтаксисом, если вы просто напишите:
addUhum(_)