传入运算符作为参数

Passing in An Operator as a Parameter

我正在做 "Scala for the Impatient" 第 14 章第 8 题的练习:

本质上,我需要创建一个函数(利用模式匹配)接收运算符和节点,并输出运算结果。例如。 Node(+, Node(*, Leaf(2), Leaf(3)) Leaf(1)) 应该输出 7.

这里有一些给定的 classes:

sealed abstract class BinaryTree
case class Leaf(value: Int) extends BinaryTree

所以我创建了一个节点 class,但我很难弄清楚如何传入运算符。

case class Node(op: Function (what goes here?) , leaves: BinaryTree*) extends BinaryTree

我想像这样使用模式匹配:

  tree match {
    case Node(op, leaves @ _*) => op match {
      case op : Function => leaves.reduceLeft(_ op _)
    }
    case leaf: Leaf => leaf.value

但是

case op : Function => leaves.reduceLeft(_ op _)

部分错误。我不知道如何使用在节点 class 中传递的运算符。我在这里做错了什么?

我假设运算符将始终是二进制的,因此,我们所谓的 BinaryTree 将至少有两个操作数:

  trait BinaryTree

  case class Leaf(value: Int) extends BinaryTree

  case class Node(op: Function2[Int, Int, Int], l1: BinaryTree*) extends BinaryTree

  object Operators {
    val + = (a: Int, b: Int) => a + b
    val * = (a: Int, b: Int) => a * b
  }

  def f(tree: BinaryTree): Int = {
    tree match {
      case n: Node => n.l1.map(f).reduceLeft((r,c) => n.op(r,c))
      case leaf: Leaf => leaf.value
    }
  }

部分测试结果:

简单的一个:

scala>   f(Node(Operators.*,Leaf(4),Leaf(2),Leaf(3)))
res4: Int = 24

scala> f(Node(Operators.+, 
         Node(Operators.*, Leaf(2), Leaf(1), Leaf(4), Leaf(5)), Leaf(6)))
res5: Int = 46

scala>   f(Node(Operators.+, 
          Node(Operators.*, Leaf(2), Leaf(1), Leaf(4), Leaf(5)),
          Node(Operators.+,Leaf(9),Leaf(9)), Leaf(6)))
res6: Int = 64

相当复杂:

scala> f(Node(Operators.+,
          Node(Operators.*, Leaf(2), Leaf(1), 
          Node(Operators.* ,Leaf(4), Leaf(5) ,Leaf(2))),
          Node(Operators.+,Leaf(9),Leaf(9)), Leaf(6),
          Node(Operators.*, Leaf(2), Leaf(2))))
res7: Int = 108

它有更优雅的解决方案,但由于您需要模式匹配:

sealed abstract class BinaryTree
case class Leaf(value: Int) extends BinaryTree
case class Node(op: (Int, Int) => Int , leaves: BinaryTree*) extends BinaryTree

def calc(tree: BinaryTree): Int = tree match {
  case Leaf(v) => v
  case Node(op, h, leaves @ _*) => leaves.foldLeft(calc(h))((a,b) => op(a,calc(b)))
}

object Operators {
  def +(a: Int, b: Int): Int = a + b
  def *(a: Int, b: Int): Int = a * b
}

val tree = Node(Operators.+, Node(Operators.*, Leaf(9), Leaf(3)), Leaf(1))

calc(tree)