Функциональная композиция методов, функций и частично применяемых функций в Scala - PullRequest
17 голосов
/ 07 октября 2011

Чем-то похож на вопрос переполнения стека Методы Compos и andThen , я изучал учебник Twitter Scala * в Твиттере и быстро столкнулся с той же проблемой, что иу комментатора был (что было здорово, потому что я пошел спать, думая, что моя проблема была решена).

В учебном пособии он определяет два метода как таковые:

def addUmm(x: String) = x + " umm"
def addAhem(x: String) = x + " ahem"

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

scala> ((s: String) => s + " umm").compose((s: String) => s + " ahem")
res0: String => java.lang.String = <function1>

Круто. Проблема в том, что, когда у меня нет возможности сочинять методы, имеет смысл, когда я то же самоесо значениями, которые я знаю, оцениваются как Function1:

val a = (s: String) => s + " umm"
val b = (s: String) => s + " ahem"
val c = a(_).compose(b(_))

Что ж, эта последняя строка выдает ту же ошибку, что и исходный вопрос, даже если они частично применяютсяна этот раз функций, а не методов.Один из ответов в исходном вопросе (высоко оцениваемый, но не принятый ответ), по-видимому, намекает на то, как это связано с расширением частичного применения, каково объяснение?

Для новичка в Scala тот факт, что эксперт выводит a(_).compose(b(_)) неправильно, независимо от того, явно ли вы указали _: String оба места, но a.compose(b) делает, несколько сбивает с толку.

Ответы [ 2 ]

24 голосов
/ 07 октября 2011

a(_).compose(b(_)) расширяется до x => { a(x).compose(y => b(y) }. Отсюда и ошибка. То, что вы хотите, это (x => a(x)).compose(y => b(y)). Добавление пары скобок исправляет это.

scala> (a(_)).compose(b(_: String))
res56: String => java.lang.String = <function1>

scala> res56("hello")
res57: java.lang.String = helloahemumm

Но поскольку a и b являются функциями, вы можете избежать всего этого и просто сделать a compose b.

4 голосов
/ 07 октября 2011

Вы можете использовать просто 'a compose b'.

scala> val c = a compose b
c: String => java.lang.String = <function1>
...