在scala中,如何找到函数中定义的子例程的调用



假设我有一个函数/方法:

class A {
def function() = {
   subroutine("A")
   ...
   subroutine("B")
   ...
   subroutine("C")
}
def subroutine(a: String) = { ... }
}

是否可以使用Scala反射式编程来查找function()中子程序(a:String)的所有3次调用,而不调用function()本身?(这可能需要很长的过程)

您可以尝试通过一些很酷的功能工具在不进行内省的情况下解决这个问题。

让我们使用scalaz库,它有一个特殊的类型类Arrow,它是Function的抽象
它几乎可以做任何你通常用函数做的事情
因此,让我们定义一种特殊的类型,它不仅包含函数,而且以某种可读的方式包含调用层次结构。

import scalaz._
import scalaz.syntax.tree._
import scalaz.std.function._
import scalaz.syntax.arrow._
import scalaz.std.string._
case class Subroutine[-A, +B](hier: Seq[Tree[String]], run: A => B) {
  def named(name: String) = Subroutine(Seq(name.node(hier: _*)), run)
  def printHier = hier.map(_.drawTree).mkString("n" + "V" * 15 + "n")
}
object Subroutine {
  def named[A, B](tag: String)(run: A => B) = Subroutine(Seq(tag.leaf), run)
  implicit def anon[A, B](run: A => B) = Subroutine(Seq.empty, run)
  implicit object subroutineArrow extends Arrow[Subroutine] {
    def arr[A, B](f: (A) => B): Subroutine[A, B] = anon(f)
    def first[A, B, C](f: Subroutine[A, B]): Subroutine[(A, C), (B, C)] =
      Subroutine(f.hier, f.run.first[C]).named("$1->")
    override def second[A, B, C](f: Subroutine[A, B]): Subroutine[(C, A), (C, B)] =
      Subroutine(f.hier, f.run.second[C]).named("$2->")
    def id[A]: Subroutine[A, A] = anon(identity)
    def compose[A, B, C](f: Subroutine[B, C], g: Subroutine[A, B]): Subroutine[A, C] =
      Subroutine(g.hier ++ f.hier, f.run compose g.run)
  }
}

现在让我们定义一些子程序

import Subroutine._
val square = { (x: Double) => x * x } named "square"
val sqrt = math.sqrt _ named "sqrt"
val sum = Subroutine.named[(Double, Double), Double]("sum"){ case (x, y) => x + y}
val abs = ((square *** square) >>> sum >>> sqrt) named "abs"

从这里你可以验证

abs.run(3,4)

给出结果5.0

abs.printHier

像一样给出有趣的调用顺序

"abs"
|
+- "$1->"
|  |
|  `- "square"
|
+- "$2->"
|  |
|  `- "square"
|
+- "sum"
|
`- "sqrt"

甚至定义

def pack22[X] = Subroutine.anon[(X, X, X, X), ((X, X), (X, X))] { case (a, b, c, d) => ((a, b), (c, d)) }
val abs4 = ((abs *** abs) >>> abs <<< pack22[Double]) named "abs4"

并评估

abs4.run(15, 20, 36, 48)

abs4.printHier

相关内容

  • 没有找到相关文章

最新更新