Союз двух наборов в Scala

Из вопроса, связанного здесь, я нашел эту реализацию Союза в Scala:

def union(a: Set, b: Set): Set = i => a(i) || b(i)

И Set - это функция типа:

type Set = Int => Boolean

Теперь я понимаю, что в Scala здесь функция отображается от Int до Boolean, и я также понимаю, как этот оператор выполняется:

a(i) || b(i)

Но я не понимаю, что такое "я" здесь. От куда это? И когда он находит соответствие между наборами, он возвращает true, если это действительно так, где его фильтровать?

Ответы

Ответ 1

Скажем, у нас есть объект, называемый SoSet, указанный

object SoSet {
    type Set = Int => Boolean
    val a : Set = ???
    val b : Set = ???
    def isItem(item : Int) = a(item) || b(item)
}

Подпись isItem задается Int => Boolean, которая является Set. Все идет нормально.

Но теперь мы просто хотим вернуть функцию isItem (т.е. a Set).

Итак, давайте определим для этого функцию union (сейчас нет параметров. Мы добавим ее позже).

object SoSet {
    //..   
     def union : Set = isItem // returns the function isItem
}

Теперь давайте переформатируем isItem в анонимную функцию .

object SoSet {
    //..   
    def union : Set = {
      (item : Int) => a(item) || b(item)
    }
}

Переместим Set a and b из object SoSet в параметры def union. Рефакторинг item до i.

object SoSet { 
   type Set = Int => Boolean
   def union(a : Set, b : Set) : Set = (i : Int) => a(i) || b(i)
}

ОБНОВЛЕНИЕ

 val s1 = Set(1, 2, 3)                           
 val s2 = Set(2, 3, 4)     
 val s3 = union(s1, s2) //  returns the function..  Int => Boolean = <function1>
 s3(2)  // invokes the function & checks if 2 is present in the union     

Ответ 2

Set (который является только функцией), который возвращается из union, принимает некоторое целое число как параметр; вы должны дать ему произвольное имя, чтобы вы могли ссылаться на него в теле функции. Это может иметь смысл, если вы напишете такую ​​функцию следующим образом:

def union(a: Set, b: Set): Set = {
  (i) => a(i) || b(i)
}

Это может иметь еще больший смысл, если вы пишете это следующим образом:

def union(a: Set, b: Set): Set = {
  // The union of two sets is a new function that takes an Int...
  def theUnion(i: Int): Boolean = {
    // and returns true if EITEHR of the other functions are true
    a(i) || b(i)
  }

  // Now we want to return the NEW function
  theUnion
}

Опять же, i является произвольным и может быть заменен любой переменной:

def union(a: Set, b: Set): Set = item => a(item) || b(item)

[Обновление]

Поскольку мы представляем наборы как функции, нет необходимости итерации, чтобы увидеть, содержат ли они число. Например, здесь набор, содержащий любое число ниже -5:

val belowNegFive: Set = (i) => i < -5

Когда мы вызываем эту функцию с числом, она сообщит нам, является ли это число в наборе. Обратите внимание, что мы на самом деле не указали конкретные числа, которые были в наборе:

scala> belowNegFive(10)
res0: Boolean = false

scala> belowNegFive(-100)
res1: Boolean = true

scala> belowNegFive(-1)
res2: Boolean = false

Здесь другой набор, который включает любое число между 50 и 100:

val fiftyToHundred: Set = (i) => i >= 50 && i <= 100

scala> fiftyToHundred(50)
res3: Boolean = true

scala> fiftyToHundred(100)
res4: Boolean = true

scala> fiftyToHundred(75)
res5: Boolean = true

scala> fiftyToHundred(49)
res6: Boolean = false

Теперь объединение множеств belowNegFive и fiftyToHundred будет содержать любое число, которое находится ниже -5 или между 50 и 100. Мы можем легко представить это в коде, возвращая новую функцию, которая сама возвращает true, если одна из двух других функций возвращает true.

scala> val unionOfBoth: Set = (i) => belowNegFive(i) || fiftyToHundred(i)
unionOfBoth: Int => Boolean = <function1>

scala> unionOfBoth(-10)
res7: Boolean = true

scala> unionOfBoth(50)
res8: Boolean = true

scala> unionOfBoth(0)
res9: Boolean = false

Функция union из вашего вопроса - это всего лишь способ применить этот шаблон в общем случае к любым двум наборам.

Ответ 3

И когда он находит соответствие между наборами, он возвращает true, если это действительно так, где его фильтровать?

union не находит совпадения между двумя наборами, он создает новый набор, который содержит значения оба набора. Пример:

val a = (i) => i == 2 // a contains 2 as a(2) == True
val b = (i) => i == 5 // b contains 5 as b(5) == True
val u = union(a, b)   // u contains 2 and 5 as u(2) == True and u(5) == True

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

Пример запроса значений объединения:

val a = (i) => i == 2
val b = (i) => i == 5
val u = union(a, b)

for(i <- 1 to 10 if u(i)) yield i     // returns Vector(2, 5)

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