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

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

46 голосов
/ 21 сентября 2011

Я следую учебному пособию Сопоставление с образцом и функциональная композиция по методам 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 ]

49 голосов
/ 22 сентября 2011

Ну, это:

addUhum _

это расширение eta. Преобразует методы в функции. С другой стороны, это:

addUhum(_)

- анонимная функция. Фактически, это частичное применение функции, в котором этот параметр не применяется, и все это преобразуется в функцию. Расширяется до:

x => addUhum(x)

Точные правила расширения немного сложно объяснить, но, в принципе, функция «запустится» в самом внутреннем разделителе выражения. Исключение составляют приложения с частичной функцией, где «x» перемещается за пределы функции - если вместо параметра используется _.

Во всяком случае, вот как это расширяется:

val ummThenAhem = x => addAhem(x).compose(y => addUmm(y))

Увы, механизм вывода типов не знает тип x или y. Если хотите, вы можете увидеть, что именно он пытался, используя параметр -Ytyper-debug.

42 голосов
/ 21 сентября 2011

addAhem - это метод.Метод compose определен для функций.addAhem _ преобразует addAhem из метода в функцию, поэтому compose может быть вызвано для него.compose ожидает функцию в качестве аргумента.Вы даете ему метод addUmm путем преобразования addUmm в функцию с addUmm _ (подчеркивание может быть опущено, потому что компилятор может автоматически преобразовать метод в функцию, когда он знает, что функция в любом случае ожидается).Итак, ваш код:

addAhem _ compose addUmm

совпадает с

(addAhem _).compose(addUmm)

, но не

addAhem(_).compose(addUmm(_))

PS Я не смотрел предоставленную вами ссылку.

5 голосов
/ 21 сентября 2011

Из 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>
2 голосов
/ 21 сентября 2011

Я считаю, что руководство было написано для более ранней версии Scala (возможно, 2.7.7 или более ранней).С тех пор в компиляторе произошли некоторые изменения, а именно расширения системы типов, которые теперь приводят к сбою вывода типа на:

addUhum(_).compose(addAhem(_))

Подъем к функции все еще работает с этим синтаксисом, еслиты просто пишешь:

addUhum(_)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...