你可以嘗試通過一些很酷的功能工具來解決這個問題,而不需要自省。
讓我們使用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