Сопоставление с образцами со связями (PatternA AND PatternB)

В Scala есть языковая функция, которая поддерживает дизъюнкции в сопоставлении с образцом ("Альтернативы шаблону"):

x match {
    case _: String | _: Int => 
    case _ =>
}

Однако мне часто нужно инициировать действие, если проверка удовлетворяет требованиям Pattern A и PatternB (соединение).

Я создал комбинатор шаблонов '&&', который добавляет эту возможность. Три маленькие строчки, которые напоминают мне, почему я люблю Scala!

// Splitter to apply two pattern matches on the same scrutiny.
object && {
  def unapply[A](a: A) = Some((a, a))
}

// Extractor object matching first character.
object StartsWith {
  def unapply(s: String) = s.headOption
}

// Extractor object matching last character.
object EndsWith {
  def unapply(s: String) = s.reverse.headOption
}

// Extractor object matching length.
object Length {
  def unapply(s: String) = Some(s.length)
}

"foo" match {
  case StartsWith('f') && EndsWith('f') => "f.*f"
  case StartsWith('f') && EndsWith(e) && Length(3) if "aeiou".contains(e) => "f..[aeiou]"
  case _ => "_"
}

Очки для обсуждения

  1. Есть ли способ сделать это?
  2. Есть ли проблемы с этим подходом?
  3. Может ли этот подход создать другие полезные комбинаторы? (например, Not)
  4. Нужно ли добавлять такой комбинатор в стандартную библиотеку?

ОБНОВЛЕНИЕ Меня только что спросили, как компилятор интерпретирует case A && B && C, Это шаблоны инфиксных операторов (раздел 8.1.9 Справочника Scala). Вы также можете выразить это с помощью стандартных шаблонов извлечения (8.1.7) как &&(&&(A, B), C).' Notice how the expressions are associated left to right, as per normal infix operator method calls likeBoolean # &&inval b = true && false && true`.

2 ответа

Решение

Мне очень нравится этот трюк. Я не знаю ни одного существующего способа сделать это, и я не предвижу никаких проблем с этим - хотя это не значит много. Я не могу придумать способ создать Not,

Что касается добавления его в стандартную библиотеку... возможно. Но я думаю, что это немного сложно. С другой стороны, как насчет того, чтобы убедить людей Скалаза включить это? Это больше похоже на их собственный бейливик.

Возможная проблема с этим - раздутый перевод, который генерирует сопоставитель шаблонов. Вот перевод примера программы, созданной с scalac -print, Четное -optimise не может упростить if (true) "_" else throw new MatchError() выражения.

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

Если && был встроен в язык, возможно, перевод мог бы быть умнее. В качестве альтернативы, небольшие улучшения -optimise мог бы помочь.

Другие вопросы по тегам