Синтаксис анонимной функции Scala

Я узнаю больше о 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)?

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

3 ответа

Решение

Это забавная штука в функциональном программировании, называемая каррингом. По сути, Моисей Шенфинкель и последний Хаскелл Карри (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) call (обратите внимание, что следующий синтаксис 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} - который является действительным Скала.

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

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

В этом примере 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, _)))
Другие вопросы по тегам