Почему класс списка Scala называется :: - PullRequest
13 голосов
/ 06 октября 2011

Почему реализация списка scala названа ::, а не именем класса? Есть ли какой-то особый смысл за этим?

Ответы [ 3 ]

22 голосов
/ 06 октября 2011

Связанный список состоит из двух случаев: ячейка минусов (с головой и хвостом) и пустой список.Эти случаи называются :: и Nil соответственно в Scala, как и в других языках с наследием ML.В неизменяемой реализации наиболее естественная кодировка выглядит примерно так:

sealed trait List[+A]

case class Cons[+A](head: A, tail: List[A]) extends List[A]
case object Nil extends List[Nothing]

Это прекрасно работает, и в этом нет ничего плохого.Вы можете определить метод :: для List (или prepend, если хотите), и все будет работать так, как вы ожидаете.В этом случае «конкретная реализация» List будет Cons, хотя технически и Cons, и Nil являются конкретными реализациями.

Но вот проблема: мы хотим иметь возможностьсопоставление с образцом в экземпляре List для возврата содержимого.В сложившейся ситуации для такого сопоставления с образцом потребуется следующий синтаксис:

def sum(xs: List[Int]): Int = xs match {
  case Cons(hd, tl) => hd + sum(tl)
  case Nil => 0
}

Хотя это немного уродливо.Что мы действительно хотим, так это иметь возможность использовать оператор :: в нашем сопоставлении с образцом точно так же, как мы используем его при первоначальном построении списка.Вот почему класс Cons назван ::.

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

sealed trait List[+A]

case class ::[+A](head: A, tail: List[A]) extends List[A]
case object Nil extends List[Nothing]

def sum(xs: List[Int]): Int = xs match {
  case hd :: tl => hd + sum(tl)
  case Nil => 0
}

Именно поэтому любой экземпляр List, имеющий содержимое, будет экземпляром класса ::, так как этонепустая реализация List.

21 голосов
/ 06 октября 2011

Это для работы с сопоставлением с образцом. У вас есть нечто, называемое Шаблоны инфиксных операторов , где шаблон p op q эквивалентен шаблону конструктора или экстрактора op(p, q).

Таким образом, класс case :: определяет конструктор ::(head, tail). Это позволяет вам соответствовать так:

list match {
  case ::(head, tail) =>
}

Но с помощью шаблона инфиксного оператора вы можете написать более знакомый синтаксис:

list match {
  case head :: tail =>
}

Обратите внимание, что поиск в стеке потока по "шаблону оператора инфиксного скрипта [scala] * возвращает похожие вопросы и дополнительные варианты использования шаблона.

3 голосов
/ 06 октября 2011

Это стандартное имя оператора cons, добавляющее элемент в список.

...