Составь и потом методы

Я следую инструкциям по сопоставлению шаблонов и функциональной композиции в 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(_)
Другие вопросы по тегам