Функциональный состав методов, функций и частично применяемых функций в Scala

В некоторой степени похожий на вопрос Compose и andThen методы, я работал через Twitter Scala School и быстро столкнулся с той же проблемой, что и у комментатора (что было здорово, потому что я ложился спать, думая, что моя проблема решена).

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

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

а в более новых версиях Scala вы не можете называть их как таковые: 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) делает несколько сбивает с толку.

Ответы

Ответ 1

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.

Ответ 2

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

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