Когда использовать частично прикладные функции

Примечание: перейдите к "Вопросу" ниже, если вы просто хотите пропустить контекст

Когда вы беседуете о Scala, я в значительной степени даю "игрушечные проблемы", подобные приведенным ниже, в качестве примеров частично прикладных функций.

def multiply(x:Int, y:Int): Int = x * y
val x5 = multiply(5, _:Int)
x5(10) //produces 50

Этот пример помогает, однако мне сложно объяснить общее "это когда вы узнаете, когда использовать частично прикладную функцию".

Вопрос. У каждого есть свой способ успешного объяснения частично прикладных функций, которые действительно попадают домой для разработчиков Java (или других OO)?

Ответы

Ответ 1

Предположим, вы хотите применить налог с продаж.

def withTax(cost: Float, state: String) = { /* Some complicated lookup table */ }

Теперь предположим, что вы хотите сделать кучу покупок в Нью-Йорке.

val locallyTaxed = withTax(_: Float, "NY")
val costOfApples = locallyTaxed(price("apples"))

Вы получаете максимальное повторное использование кода из исходного метода, но максимальное удобство для повторяющихся задач не должно указывать параметры, которые (локально) всегда одинаковы.

Люди часто пытаются решить это с помощью implicits:

def withTax(cost: Float)(implicit val state: String) = ...

Не делай этого! (Не без тщательного рассмотрения.) Трудно следить за тем, какой неявный val случается вокруг в то время. С частично примененными функциями вы получаете такую ​​же экономию при наборе текста, плюс вы знаете, какой из них вы используете, потому что вы вводите имя каждый раз, когда используете его!

Ответ 2

В Java вы часто передаете первые (или более) аргументы частично применяемой функции конструктору класса. Пример Rex может выглядеть примерно так:

class TaxProvider {
    final String state;

    TaxProvider(String state) {
        this.state = state;
    }

    double getTaxedCost(double cost) {
      return ... // look up tax for state and apply to cost
    }
}


TaxProvider locallyTaxed = new TaxProvider("NY")
double costOfApples = locallyTaxed.getTaxedCost(price("apples"))

Ответ 3

Я предполагаю, что Scala имеет состав функции, это то, что частично прикладывает функции.

Другим пунктом являются функции более высокого порядка, такие как filter, которые берут предикат, и их использование, как в:

filter (<42) list  -- sorry, don't speak Scala

Предикат часто является частью частично применяемой функции. То же самое верно для map, fold и т.д.