Использование произвольных деревьев с Free Monads в Scala+Cats

Я создаю библиотеку для грамматик, которая будет иметь 2 разные интерпретации: 1) разбор строк на основе грамматики 2) создание строк на языке, определенном грамматикой.

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

Мне удалось реализовать свои деревья с помощью оператора ~ для обозначения двух объединенных грамматик. Таким образом, AST представляет собой список грамматик, которые сами по себе являются произвольными AST.

Мой вопрос: каков хороший способ рекурсии поддеревьев AST в свободной монаде?

Моя текущая реализация здесь:< /а>

 def parserInterpreter: GrammarA ~> ParserInterpreterState =
new (GrammarA ~> ParserInterpreterState) {
  def apply[A](fa: GrammarA[A]): ParserInterpreterState[A] =
    fa match {
      case Regx(regexp) => parseRegex(regexp)
      case Optional(b)  => parseOptional(b.foldMap(this))
      case m @ Multi(g) =>
        def x: State[String, A] =
          State.apply(state => {
            g.foldMap(this)
              .run(state)
              .map {
                case (s, ParseSuccess(_))    => x.run(s).value
                case r @ (s, ParseFailure()) => (s, ParseSuccess(s).asInstanceOf[A])
              }
              .value
          })
        x
      case Choice(a, b) =>
        State.apply(state => {
          val runA = a.foldMap(this).run(state).value
          if (runA._2.asInstanceOf[ParseResult[_]].isSuccess)
            runA
          else {
            b.foldMap(this).run(state).value
          }
        })
    }
}

Обратите особое внимание на то, что в случае Multi используется небезопасная рекурсия (т. е. не хвостовая рекурсия) для рекурсивной интерпретации поддерева. Есть лучший способ это сделать?

Нажмите здесь, чтобы просмотреть исходный код.


person Felix    schedule 10.10.2016    source источник
comment
Этот вопрос кажется связанным, но для scalaz вместо кошек: stackoverflow.com/questions/32046874/   -  person theStrawMan    schedule 15.06.2018


Ответы (1)


Если вы создаете библиотеку принтеров Parser/Pretty, объекты, которыми вы манипулируете, вероятно, не являются монадами. Вместо этого вы можете использовать кошачий InvariantMonoidal (и его бесплатный аналог FreeInvariantMonoidal). В соответствующем руководстве есть раздел о кодеках, которые могут вас заинтересовать.

person OlivierBlanvillain    schedule 10.11.2016