2015-11-13 42 views
2

假設我有一個功能/方法定義子程序的調用:Scala中,如何找到在功能

class A { 

def function() = { 
    subroutine("A") 
    ... 
    subroutine("B") 
    ... 
    subroutine("C") 
} 

def subroutine(a: String) = { ... } 

} 

是否有可能使用的Scala反射編程查找子程序的所有3次調用(一個:字符串)在函數(),而不調用函數()本身? (這可能需要很長的過程)

+0

有什麼用例?你只想找到靜態事件?例如,如果一個人在一個循環中被多次調用,或者因爲一個條件而根本沒有被調用,會發生什麼? –

+0

嗨保羅:是的,我只是想找到靜態的發生(理論上編譯時間的宇宙可以處理),無論它們是否實際調用。 – tribbloid

+0

你爲什麼要這樣做?它是一個分析scala代碼的工具,還是用於程序運行時的一些控制流程? – jazmit

回答

1

你可以嘗試通過一些很酷的功能工具來解決這個問題,而不需要自省。

讓我們使用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 
+0

非常感謝我向我介紹這個驚人的庫!但不幸的是,在我的情況下,函數「abs」是一個用普通的scala編寫的數千行代碼的複雜算法,並且可能由不同的人擴展。所以解決方案只能證明其規模小得多。 – tribbloid