你可以尝试通过一些很酷的功能工具来解决这个问题,而不需要自省。
让我们使用scalaz library它有特殊的类型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
有什么用例?你只想找到静态事件?例如,如果一个人在一个循环中被多次调用,或者因为一个条件而根本没有被调用,会发生什么? –
嗨保罗:是的,我只是想找到静态的发生(理论上编译时间的宇宙可以处理),无论它们是否实际调用。 – tribbloid
你为什么要这样做?它是一个分析scala代码的工具,还是用于程序运行时的一些控制流程? – jazmit