Я изучаю Скалу, работая над упражнениями из книги «Скала для нетерпимого». Один вопрос спрашивает:Scala: Есть ли лучший способ оценить дерево выражений?
/**
* Q8: Extends the tree in the preceding exercise so that each non-leaf node stores an operator in addition to
* the child nodes. Then write a function `eval` that computes the value. For example, the tree
*
* +
* * 2 -
* 3 8 5
*
* has a value (3 * 8) + 2 + (-5) = 21
*
*/
Мое решение заключается в следующем. Вы можете улучшить его? В частности, мне интересно, есть ли способ прямого сопоставления с функциями вместо имен методов. Например, если я мог бы написать что-то вроде следующего мысленного заявления
case ExprTreeNode(f, children @ _*) if (f == Int.+ || f == Int.-) => children.foldLeft(0) { (acc, elem) => eval(elem) f acc }
тогда я мог бы объединить +
и -
случаев. То же самое касается *
и /
.
sealed abstract class ExpressionTree
case class ExprTreeLeaf(value: Int) extends ExpressionTree
case class ExprTreeNode(op: String, children: ExpressionTree*) extends ExpressionTree
def eval(expr: ExpressionTree): Int = expr match {
case ExprTreeNode("+", children @ _*) => children.foldLeft(0) { _ + eval(_) }
case ExprTreeNode("*", children @ _*) => children.foldLeft(1) { _ * eval(_) }
case ExprTreeNode("/", children @ _*) => children.foldLeft(1) { (acc, elem) => eval(elem)/acc }
case ExprTreeNode("-", child) => eval(child).unary_- // Order matters here, 'children @ _*' would match 1 child
case ExprTreeNode("-", children @ _*) => children.foldLeft(0) { (acc, elem) => eval(elem) - acc }
case leaf: ExprTreeLeaf => leaf.value
}
Тестовый пример:
"Method eval" should "evaluate an expression tree" in {
val expr = ExprTreeNode("+", ExprTreeNode("*", ExprTreeLeaf(3), ExprTreeLeaf(8)), ExprTreeLeaf(2), ExprTreeNode("-", ExprTreeLeaf(5)))
eval(expr) should be(21)
}
Не уверен, что вы имеете в виду ... '' + "', '" * "', ... не являются функциями, просто 'String'. Вы можете создать 'Map' /' Function1' из этих 'String' в нужные вам функции и использовать их в fold (также для нейтрального элемента). –
@ GáborBakos Я спрашиваю, могу ли я использовать ссылки на методы для операторов вместо того, чтобы использовать строки. Если бы я мог, я бы определил 'ExprTreeNode' следующим образом: ' class class ExprTreeNode (op: (Int, Int) => Int, дети: ExpressionTree *) extendsTree' Карта метода не покупает меня много стоимость. –