Как избавиться от непроверенного из-за предупреждения о стирании при сопоставлении с образцом

Скала 2.8.1

Я реализовал очень простой внешний DSL, используя парсер/комбинатор для контроля качества, чтобы написать приемочные тесты.

Недавно я добавил возможность зацикливаться на наборе выражений, например так

sealed trait Expr

...
//insert other case classes extending 'Expr' here
...

case class Repetition(times: Int, expressions: List[Expr]) extends Expr

class TestFixtureParser(....) extends RegexParsers {
  val repeatParser: Parser[Expr] = (l("repeat") ~> number) ~ (l("{") ~> expressions <~ l("}")) ^^ {
    case (times: Int) ~ (exprs: List[Expr]) => {
      Repetition(times, exprs)
    }
  }

  private val expressions: Parser[List[Expr]] = (repeatParser | 
    /*insert other Parser[Expr]s '|' together here */ | verifyParser ).*

}

При построении я получаю предупреждение warning: non variable type-argument ... is unchecked since it is eliminated by erasure при сопоставлении с образцом. Я также попытался извлечь, используя следующее.

  //Doesn't build with error
  /*
    error: missing parameter type for expanded function ((x0$2) => x0$2 match {
      case $tilde((times @ _), (exprs @ _)) => Repetition(times, exprs)
    })
        r: ~[Int, List[Expr]] => {
  */
  val repeatParser: Parser[Expr] = (l("repeat") ~> number) ~ (l("{") ~> expressions <~ l("}")) ^^ {
    r: ~[Int, List[Expr]] => {
      case times ~ exprs =>
        Repetition(times, exprs)
    }
  }

  //Actually this does build without warning. 
  //I am unfortunately using intelliJ and it doesn't like it
  val repeatParser: Parser[Expr] = (l("repeat") ~> number) ~ (l("{") ~> expressions <~ l("}")) ^^ {
    repetitions: ~[Int, List[Expr]] => {
      val ~(times, exprs) = repetitions
      Repetition(times, exprs)
    }
  }

  //Builds but same warning
  val repeatParser: Parser[Expr] = (l("repeat") ~> number) ~ (l("{") ~> expressions <~ l("}")) ^^ {
    repetitions => {
      val ~(times: Int, exprs: List[Expr]) = repetitions
      Repetition(times, exprs)
    }
  }

Есть ли у кого-нибудь предложения по извлечению exprs элегантным способом без этого предупреждения? Он работает как есть. Должен ли я просто игнорировать это? Я бы не хотел иметь привычку игнорировать предупреждения.

Редактировать: Ответ. На самом деле это было то, что я попробовал сначала, но затем добавил типы, потому что плагин intelliJ scala не мог их вывести.

  val repeatParser: Parser[Expr] = (l("repeat") ~> number) ~ (l("{") ~> expressions <~ l("}")) ^^ {
      case times ~ exprs =>
          Repetition(times, exprs)
  }

person drstevens    schedule 15.11.2011    source источник
comment
Мне интересно, почему ваш первый пример для not build не строится... Я думаю, Scala сможет вывести типы в выражении case. Какая у вас ошибка?   -  person Owen    schedule 16.11.2011


Ответы (2)


Я думаю, что ваш синтаксис не подходит для первого примера «не строит» (похоже, вы возвращаете частичную функцию, а не применяете ее, а это не то, что вам нужно). Попробуйте написать:

val repeatParser: Parser[Expr] = (l("repeat") ~> number) ~ (l("{") ~> expressions <~ l("}")) ^^ {
    case times ~ exprs =>
        Repetition(times, exprs)
}

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

person Owen    schedule 15.11.2011

Принятый ответ - лучший, но вот альтернативы, когда это не работает:

r: ~[t1, t2] => {
  case times ~ exprs =>
    Repetition(times, exprs)
}

Выше t1 и t2 предполагаются, и они могут быть просто выведены как Any. Однако, к чему бы они ни выводились, это лучшее, что вы можете сделать с этим синтаксисом.

val ~(times: Int, exprs: List[t]) = repetitions

Здесь, поскольку вы извлекаете значения, вы можете фактически проверить типы. Вы не проверяете, есть ли у вас ~[Int,List[Int]] — вы проверяете, имеют ли извлеченные значения типы Int и List[t]. Обратите внимание, что предупреждение, которое вы получили, пришло от параметра типа к List.

person Daniel C. Sobral    schedule 16.11.2011
comment
Да, я полностью понимаю вещь о стирании. Единственная разница между тем, что у меня было в моем коде, и принятым ответом заключается в том, что у меня есть явные типы. Проблема в том, что на данный момент я слишком полагаюсь на плагин IntelliJ scala. Он пожаловался красной волнистой линией на то, что типы для ~ не могут быть здесь выведены. Компилятор говорит об обратном. Это здорово помогло мне выучить язык за последние 8 месяцев или около того, но по мере того, как я использую более продвинутые конструкции, инструменты рефакторинга и контекстная помощь начинают переставать работать должным образом. - person drstevens; 16.11.2011
comment
@drstevens Я не уверен, что мы говорим об одном и том же. Когда я пишу ~[t1, t2], я очень точен: использование здесь строчных букв указывает компилятору, что он должен вывести типы и присвоить их t1 и t2. - person Daniel C. Sobral; 16.11.2011
comment
Вы правы, мы не об одном и том же говорили. Я не знал, что параметр типа нижнего регистра имеет здесь значение. Мне нужно понять это больше. Спасибо, что ответили на это. - person drstevens; 16.11.2011
comment
@drstevens Мне потребовалось более двух лет, чтобы узнать об этом самому, это довольно неясно. Обратите внимание, что здесь относится к сопоставлению с образцом. Он также не будет работать с объявлениями val, если только он не встречается внутри шаблона (например, val Some(t: ~[t1, t2]) = .... - person Daniel C. Sobral; 16.11.2011