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

时间:2015-11-13 18:50:11

标签: scala reflection

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

class A {

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

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

}

是否可以使用Scala反射编程在函数()中查找子程序(a:String)的所有3个调用,而不调用function()本身? (这可能需要很长的时间)

1 个答案:

答案 0 :(得分:1)

您可以尝试通过一些很酷的功能工具来解决这个问题,而不需要内省。

让我们使用scalaz library它有特殊的类型Arrow,它是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

<!DOCTYPE html>
<html>
    <head>
    <title>Slideout menu</title>
    <style>
        .menu{
            overflow-x: hidden;
            position: relative;
            left: 0;
        }
        .menu-open{
            left: 231px;
        }
        .menu-open .menu-side{
            left: 0;
        }
        .menu-side,.menu{
            -webkit-transition: left 0.2s ease;
            -moz-transition: left 0.2s ease;
            transition: left 0.2s ease;
        }
        .menu-side{
            background-color: #333;
            border-right: 1px solid #000;
            color:#fff;
            position: fixed;
            top: 0;
            left: -231px;
            width: 210px;
            height: 100%;
            padding: 10px;
        }
    </style>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body class="menu">
    <header>
        <a href="#" class="menu-toggel">toggel button</a>
        <nav class="menu-side">
            this is a site menu
            <form action="" method="post">
                <input type="text" name="titel" value="data to send when submit" id="name">
                <input type="submit" value="register">
            </form>
        </nav>
    </header>
    <form action="" method="post">
        <label for="titel">Titel</label>
        <input type="text" name="titel" value="data to send when submit" id="name">
        <label for="omschrijving">omschrijving</label>
        <input type="text" name="omschrijving" id="omschrijving" value="data to send when submit" autocomplete="off">
        <label for="email">Uw emailadres</label>
        <input type="text" name="email" id="email" value="data to send when submit">
        <label for="naam">Uw naam</label>
        <input type="text" name="naam" id="naam" value="data to send when submit">
    </form>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
    (function() {
        var body = $('body');
        $('.menu-toggel').bind('click', function(){
           body.toggleClass('menu-open');
           return false;
        });
    })();
</script>