Соответствие тематических классов в scala: ~ (a, b) match {case a ~ b => ...} - PullRequest
6 голосов
/ 14 июля 2010

У меня есть кейс класса

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

Когда я хочу сделать соответствующее сопоставление

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))? По каким правилам?

1 Ответ

10 голосов
/ 14 июля 2010

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

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

2 & 3) Правоассоциативности указано в Спецификации языка Scala . Раздел «Операции с инфиксами»

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

Кстати, правоассоциативность - это уловка, которая позволяет создавать списки с 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)
...