Синтаксис анонимной функции Scala - PullRequest
14 голосов
/ 11 октября 2009

Я узнаю больше о Scala, и у меня возникли небольшие проблемы с пониманием примера анонимных функций в http://www.scala -lang.org / node / 135 .Я скопировал весь блок кода ниже:

object CurryTest extends Application {
    def filter(xs: List[Int], p: Int => Boolean): List[Int] =
        if (xs.isEmpty) xs
        else if (p(xs.head)) xs.head :: filter(xs.tail, p)
        else filter(xs.tail, p)

    def modN(n: Int)(x: Int) = ((x % n) == 0)

    val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
    println(filter(nums, modN(2)))
    println(filter(nums, modN(3)))
}

Я запутался с применением функции modN

def modN(n: Int)(x: Int) = ((x % n) == 0)

В примере она вызывается с одним аргументом

modN(2) and modN(3)

Что означает синтаксис modN (n: Int) (x: Int)?

Поскольку он вызывается с одним аргументом, я предполагаю, что они не оба аргументы, ноЯ не могу понять, как значения из чисел используются функцией мода.

Ответы [ 3 ]

46 голосов
/ 11 октября 2009

Это забавная вещь в функциональном программировании, которая называется curry . По сути, Моисей Шенфинкель и последний Хаскелл Карри (Schonfinkeling звучит странно, хотя ...) пришли к мысли, что вызов функции с несколькими аргументами, скажем, f(x,y) - это то же самое, что цепочка вызовов {g(x)}(y) или g(x)(y), где g - это функция, которая создает другую функцию в качестве своего выхода.

В качестве примера возьмем функцию f(x: Int, y: Int) = x + y. Вызов f(2,3) выдаст 5, как и ожидалось. Но что происходит, когда мы каррируем эту функцию - переопределите ее как f(x:Int)(y: Int) и назовите ее f(2)(3). Первый вызов f(2) создает функцию, которая принимает целое число y и добавляет к нему 2 -> поэтому f(2) имеет тип Int => Int и эквивалентна функции g(y) = 2 + y. Второй вызов f(2)(3) вызывает вновь созданную функцию g с аргументом 3, поэтому, как и ожидалось, оценивается в 5.

Другой способ увидеть это - пошаговое сокращение (функциональные программисты называют это бета-редукцией - это как функциональный способ поэтапного перехода) вызова f(2)(3) (обратите внимание, что на самом деле Scala не является действительным синтаксис).

f(2)(3)         // Same as x => {y => x + y}
 | 
{y => 2 + y}(3) // The x in f gets replaced by 2
       |
     2 + 3      // The y gets replaced by 3
       |
       5

Итак, после всего этого разговора f(x)(y) можно рассматривать как просто следующее лямбда-выражение (x: Int) => {(y: Int) => x + y} - которое является действительным Scala.

Надеюсь, все это имеет смысл - я попытался дать немного фона , почему вызов modN(3) имеет смысл:)

3 голосов
/ 11 октября 2009

Вы частично применяете функцию ModN. Применение частичной функции является одной из основных функций функциональных языков. Для получения дополнительной информации ознакомьтесь с этими статьями по Curry и Pointfree style.

2 голосов
/ 11 октября 2009

В этом примере modN возвращает функцию, которая модифицирует конкретный N. Это избавляет вас от необходимости делать это:

def mod2(x:Int): Boolean = (x%2) == 0
def mod3(x:Int): Boolean = (x%3) == 0

Две пары паренин разграничивают, где вы можете прекратить передавать аргументы методу. Конечно, вы также можете просто использовать заполнитель для достижения того же результата, даже если метод имеет только один список аргументов.

def modN(n: Int, x: Int): Boolean = (x % n) == 0

val nums = List(1, 2, 3, 4, 5)
println(nums.filter(modN(2, _)))
println(nums.filter(modN(3, _)))
...