Дополнительные части комбинатора парсеров

Я впервые использую комбинаторы парсера scala. У меня есть такая ситуация, когда у меня есть список «типов», и они могут расширять другие типы или нет. Если они это сделают, я просто создам карту между типом и его родительским типом. Если нет, я просто сопоставляю тип с «объектом». (Типы — это просто имена строк)

Они пишутся так:

type1 type2 type3 - parentType

or

type0a type0b

в этом случае они будут неявно - object

Я попытался реализовать его следующим образом, но он не компилируется. Он говорит, что ему требуется Option[~List[String, String] и он нашел ~[a,b]. Это также говорит о том, что он не может найти имена значений в первом для понимания, когда на самом деле это указано в совпадении шаблона case. Немного запутался сейчас, что на самом деле происходит.

def type_list = ((name+) ~ ("-" ~> parent_type)?) ^^ {
  case names ~ parent_type => for (name <- names) yield name -> parent_type
  case names => for (name <- names) yield name -> "object"
}

 def name = """[a-zA-Z\d]+""".r

На самом деле я просто хочу, чтобы это возвращало Map[String, String], если parent_type отсутствует, по умолчанию должно быть «объект». Как лучше к этому подойти?


person jbx    schedule 13.12.2013    source источник


Ответы (1)


Здесь происходит несколько вещей.

Во-первых, приоритет ~ и ? означает, что вместо объединения (name+), который является Parser[List[String]] с ( "-" ~> parent_type )? который представляет собой Parser[Option[String]], в который вы на самом деле все оборачиваете? и, таким образом, получить Parser[Option[~[List[String],String]], если это имеет смысл.

Самое простое решение — использовать дополнительный набор скобок.

Итак, вы хотите начать с:

def type_list = ((name+) ~ (("-" ~> parent_type)?))

Затем в функции сопоставления вы получите ~[List[String],Option[String]] со списком имен и необязательным parent_type. С точки зрения сопоставления с образцом вы всегда получаете name ~ parent_type, где последний является Option[String]. Так что в основном ваш второй шаблон недействителен.

Итак, вы можете сделать это:

def type_list = ((name+) ~ (("-" ~> parent_type)?)) ^^ {
   case names ~ Some(parent_type) => for (name <- names) yield name -> parent_type
   case names ~ None => for (name <- names) yield name -> "object"
}

Или вы можете упростить это до:

def type_list = ((name+) ~ (("-" ~> parent_type)?)) ^^ {
   case names ~ parent_type => for (name <- names) yield name -> parent_type.getOrElse("object)
}
person Steve Sowerby    schedule 13.12.2013
comment
Спасибо... Эти монады до сих пор сбивают меня с пути. Спасибо и за более простую версию. - person jbx; 14.12.2013