在scala中,如何找到函数中定义的子例程的调用
假设我有一个函数/方法:在scala中,如何找到函数中定义的子例程的调用,scala,reflection,Scala,Reflection,假设我有一个函数/方法: class A { def function() = { subroutine("A") ... subroutine("B") ... subroutine("C") } def subroutine(a: String) = { ... } } 是否可以使用Scala反射编程来查找function()中所有3个子程序调用(a:String),而不调用function()本身?(这可能需要一个很长的过程)您可以尝试通过一些很酷的功
class A {
def function() = {
subroutine("A")
...
subroutine("B")
...
subroutine("C")
}
def subroutine(a: String) = { ... }
}
是否可以使用Scala反射编程来查找function()中所有3个子程序调用(a:String),而不调用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"
及
用例是什么?是否只想查找静态事件?例如,如果一个循环中多次调用一个循环会发生什么?Hi Paul:是的,我只想找到静态事件(编译时宇宙理论上可以处理),而不管它们是否实际被调用。你为什么要这样做?它是一种分析scala代码的工具,还是在程序运行时用于某些控制流的工具?它是一种控制流,是一个库,其中scala函数可以作为API参数进行“插值”,调用每个函数都需要一些初始化过程,这些过程应该在主API之前确定。非常感谢您向我介绍这个令人惊叹的库!但不幸的是,在我的例子中,函数“abs”是一个复杂的算法,由数千行用普通scala编写的代码组成,可能会被不同的人扩展。因此,解决方案只能证明其规模小得多的成本是合理的。
abs4.run(15, 20, 36, 48)
abs4.printHier