Scala read-eval-print с использованием RegexParser без такого большого количества шаблонов? - PullRequest
1 голос
/ 02 декабря 2011

Я реализую часть программы Scala, которая принимает входные строки в форме "functionName arg1=x1 arg2=x2 ...", анализирует xi на правильные типы и затем вызывает соответствующую функцию Scala functionName(x1,x2,...).Приведенный ниже код является примером реализации с двумя функциями foo и bar, которые принимают разные типы аргументов.

Обратите внимание, что типы и имена аргументов foo и bar должны быть написаны от рукив код в нескольких местах: исходные определения функций, определяющие классы case, которые возвращает анализатор, и сами синтаксические анализаторы.Классы case, возвращаемые синтаксическим анализатором, также не делают в принципе ничего интересного - я испытываю желание просто вызвать foo и bar из синтаксического анализатора, но я чувствую, что это будет странно.

Мой вопрос: можнореализация будет упрощена?На практике у меня будет много функций со сложными типами аргументов, и я предпочел бы иметь возможность указывать эти типы как можно меньше раз, и, возможно, также не придется определять соответствующие классы дел.

type Word = String
// the original function definitions
def foo(x: Int, w: Word) = println("foo called with " + x + " and " + w)
def bar(y: Int, z: Int)  = println("bar called with " + y + " and " + z)

// the return type for the parser
abstract class Functions
case class Foo(x: Int, w: Word) extends Functions
case class Bar(y: Int, z: Int) extends Functions

object FunctionParse extends RegexParsers {
  val int = """-?\d+""".r ^^ (_.toInt)
  val word = """[a-zA-Z]\w*""".r

  val foo = "foo" ~> ("x=" ~> int) ~ ("w=" ~> word) ^^ { case x~w => Foo(x,w) }
  val bar = "bar" ~> ("y=" ~> int) ~ ("z=" ~> int) ^^ { case y~z => Bar(y,z) }
  val function = foo | bar

  def parseString(s: String) = parse(function, s)
}


def main(args: Array[String]) = {
  FunctionParse.parseString(args.mkString(" ")) match {
    case FunctionParse.Success(result, _) => result match {
      case Foo(x, w) => foo(x, w)
      case Bar(y, z) => bar(y, z)
    }
    case _ => println("sux.")
  }
}

Изменить: я должен отметить, что в моем случае конкретный формат выше для входной строки не очень важен - я рад изменить его (использовать xml или любой другой), если это приводит к более чистому, более простому коду Scala.

Ответы [ 2 ]

3 голосов
/ 02 декабря 2011

Вы хотите рефлексии, проще говоря.Отражение означает обнаружение, создание экземпляров и вызов классов и методов во время выполнения, а не во время компиляции.Например:

scala> val clazz = Class forName "Foo"
clazz: Class[_] = class Foo

scala> val constructors = clazz.getConstructors
constructors: Array[java.lang.reflect.Constructor[_]] = Array(public Foo(int,java.lang.String))

scala> val constructor = constructors(0)
constructor: java.lang.reflect.Constructor[_] = public Foo(int,java.lang.String)

scala> constructor.getParameter
getParameterAnnotations   getParameterTypes         

scala> val parameterTypes = constructor.getParameterTypes
parameterTypes: Array[Class[_]] = Array(int, class java.lang.String)

scala> constructor.newInstance(5: Integer, "abc")
res6: Any = Foo(5,abc)

Это все отражение Java.Scala 2.9 до сих пор не имеет специфичного для Scala интерфейса отражения, хотя он уже находится в разработке и вполне может быть доступен в следующей версии Scala.

0 голосов
/ 02 декабря 2011

То, что вы делаете, выглядит очень разумно. По моему мнению, единственный способ «упростить» это - иметь менее явные типы и / или использовать рефлексию для поиска соответствующей функции ...

Обновление: Ответ Даниэля является хорошим примером того, как использовать рефлексию. С точки зрения менее явных типов, вы должны иметь аргументы функции, равные Any ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...