Почему функция Set?

В Scala a Set есть функция:

trait Set[A] extends (A => Boolean)

Это делает невозможным наличие ковариантного неизменяемого Set, потому что тип A встречается в контравариантном положении. Напротив, Seq не определяется как функция. Уже есть некоторый контент о том, почему Sets и Seqs разработаны таким образом:

В одном ответе говорится, что причиной этого является математический фон. Но этот ответ не был объяснен немного больше. Итак, каковы конкретные преимущества для определения функции Set как функции или каковы были бы недостатки, если она реализована по-разному?

Ответы

Ответ 1

У набора типа Set[A] должен быть метод, который проверяет, есть ли элемент типа A в наборе. Этот метод (apply) должен иметь параметр типа A, представляющий этот элемент, и этот параметр находится в контравариантной позиции. Это означает, что множества не могут быть ковариантными в своем параметре типа A. Таким образом, это не расширение функционального интерфейса, что делает невозможным наличие ковариантных неизменяемых множеств, это наличие контравариантного метода apply.

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

В отличие от абстракции последовательности нет метода, который проверяет, находится ли элемент в последовательности, он имеет только метод индексирования - apply принимает целочисленный индекс и возвращает элемент в этом индексе. Последовательности также определяются как функции, но функции типа Int => A (которые ковариантны в A), а не A => Boolean, как наборы.

Если вы хотите узнать больше о том, как безопасность типов будет нарушена, если наборы были определены как ковариантные в своем параметре типа A, см. этот пример, в котором реализация набора делает некоторую запись частным членам по причинам кэширования поисковых запросов (ниже @uV - аннотация, которая отключает проверку дисперсии и expensiveLookup предназначена для имитации вызова дорогостоящей проверки, если элемент находится в наборе):

import annotation.unchecked.{uncheckedVariance => uV}

trait Set[+A] {
  def apply(elem: A @uV): Boolean
}

class CachingSet[+A >: Null] extends Set[A] {
  private var lastLookup: (A @uV, Boolean) = (null, false)
  private def expensiveLookup(elem: A @uV) = (elem, true)
  def apply(elem: A @uV): Boolean = {
    if (elem != lastLookup._1) lastLookup = expensiveLookup(elem)
    lastLookup._2
  }
  def lastQueriedElement: A = lastLookup._1
}

object Main extends App {
  val css = new CachingSet[String]
  val csa: CachingSet[AnyRef] = css

  csa.apply(new AnyRef)
  val s: String = css.lastQueriedElement // you'll get a ClassCastException here
}

Ответ 2

В отличие от Seq не определяется как функция.

Не верно.

Seq[T] extends (Int) => T