Функциональная композиция методов, функций и частично применяемых функций в Scala
В некоторой степени похожий на вопрос о переполнении стека и методах "Составить" и "Затем", я работал над учебным пособием по Scala School в Twitter и быстро столкнулся с той же проблемой, что и комментатор (что было здорово, потому что я лег спать, думая, что моя проблема решена).
В учебнике он определяет два метода как таковых:
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 ответа
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
,
Вы можете использовать просто "составить б".
scala> val c = a compose b
c: String => java.lang.String = <function1>