Соответствие классам случая в scala: ~ (a, b) соответствие {случай a~b => …}

У меня есть класс случая

case class ~[a,b](_1:a, _2:b)

Когда я хочу сделать соответствие pattetn

new ~("a", 25) match{
  case "a" ~ 25 =>
}

Я могу использовать его этот путь потому что "a" ~ 25 и ~("a", 25) эквивалентны. Но если я хочу соответствовать new ~("a", new ~("b", 25)) {case "a" ~ "b" ~ 25 => } проблемы начинаются. Я понимаю, что это операторы не эквивалентно. Так, как new ~("a", new ~("b", 25)) может быть представлен? Какой правила?

6
задан Ken Bloom 14 July 2010 в 20:10
поделиться

1 ответ

Это работает:

new ~("a", new ~("b", 25)) match {
  case "a" ~ ("b" ~ 25) =>
}

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

case "a" ~ "b" ~ 25

то же самое, что и

case ("a" ~ "b") ~ 25

что в вашем случае было бы неправильно.

Приложение

Вы можете получить правую ассоциативность, используя двоеточие в качестве последнего символа в имени класса/метода. Следующее компилируется и работает без круглых скобок (и вы можете опустить new, так как компилятор больше не будет путаться в $tilde$colon):

case class ~:[a,b](_1:a, _2:b)

~:("a", ~:("b", 25)) match {
  case "a" ~: "b" ~: 25 =>
}

Ответы

1) Без ключевого слова new класс case ~ затеняется unary_~, который дает побитовое отрицание аргумента. Выражение типа ~ 2 внутренне оценивается как unary_~(2) и то же самое относится к случаю ~ ("a", 1) - однако если вы не определите unary_~ для этого кортежа, это приведет к ошибке. С помощью ключевого слова new вы указываете компилятору явно искать класс с таким именем, чтобы он не запутался. (Технически, вы можете обойти это, используя $tilde("a", 1), которое является внутренним именем вашего класса case ~, но поскольку это деталь компилятора, вам, вероятно, не следует полагаться на нее.)

2 и 3) Ссылка на право-ассоциативность содержится в Scala Language Specification. Раздел 'Infix Operations'

Ассоциативность оператора определяется последним символом оператора. Операторы, заканчивающиеся двоеточием ':', являются право-ассоциативными. Все остальные операторы являются лево-ассоциативными.

Кстати, правая ассоциативность - это трюк, позволяющий создавать списки с Nil. (Nil - это пустой List, для которого определен право-ассоциативный оператор конкатенации ::)

val l: List[Int] = 1 :: 2 :: 3 :: Nil

который оценивается следующим образом

val l: List[Int] = (1 :: (2 :: (3 :: Nil)))

или, точнее, поскольку 3 :: NilNil. ::(3), так как

val l: List[Int] = ( ( Nil.::(3) ).::(2) ).::(1)
10
ответ дан 10 December 2019 в 00:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: