首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何跟踪Scala中的嵌套函数

如何跟踪Scala中的嵌套函数
EN

Stack Overflow用户
提问于 2012-11-07 19:50:50
回答 3查看 386关注 0票数 3

我想了解一下函数调用嵌套的深度。请考虑以下几点:

代码语言:javascript
复制
scala> def decorate(f: => Unit) : Unit = { println("I am decorated") ; f }
decorate: (f: => Unit)Unit

scala>  decorate { println("foo") }
I am decorated
foo

scala> decorate { decorate { println("foo") } }
I am decorated
I am decorated
foo

在最后一次电话中,我希望能够得到以下信息:

代码语言:javascript
复制
I am decorated 2x
I am decorated 1x
foo

其思想是,decorate函数知道其嵌套的深度。想法?

更新:正如尼基塔所想的那样,我的例子并不代表我真正想要的。目标不是产生字符串,而是能够通过对同一个嵌套函数的一系列调用传递某种状态。我觉得雷吉斯·吉恩·吉勒把我引向正确的方向。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-11-07 20:01:49

您可以使用动态范围模式。更确切地说,这意味着使用线程局部变量(scala的DynamicVariable正是为此完成的)来存储当前嵌套级别。请参阅我对另一个问题的回答,以获得此模式的一个部分示例:How to define a function that takes a function literal (with an implicit parameter) as an argument?

不过,只有当您想知道非常具体的方法的嵌套级别时,才适合这样做。如果您想要对任何方法都有效的通用机制,那么这是行不通的(因为每个方法都需要一个不同的变量)。在这种情况下,我能想到的唯一选择是检查堆栈,但它不仅不太可靠,而且非常慢。

UPDATE:实际上,有一种方法可以以通用的方式应用动态范围模式(对于任何可能的方法)。重要的是能够隐式地获得每个方法的唯一id。从这里开始,使用这个id作为键将一个DynamicVariable关联到该方法就是一个问题:

代码语言:javascript
复制
import scala.util.DynamicVariable
object FunctionNestingHelper {  
  private type FunctionId = Class[_]
  private def getFunctionId( f: Function1[_,_] ): FunctionId = {
    f.getClass // That's it! Beware, implementation dependant.
  }
  private val currentNestings = new DynamicVariable( Map.empty[FunctionId, Int] )
  def withFunctionNesting[T]( body: Int => T ): T = {
    val id = getFunctionId( body )
    val oldNestings = currentNestings.value 
    val oldNesting = oldNestings.getOrElse( id, 0 )
    val newNesting = oldNesting + 1
    currentNestings.withValue( oldNestings + ( id -> newNesting) ) {
      body( newNesting )
    }    
  }
}

用法:

代码语言:javascript
复制
import FunctionNestingHelper._
def decorate(f: => Unit)  = withFunctionNesting { nesting: Int =>
  println("I am decorated " + nesting + "x") ; f 
}

为了获得该方法的唯一id,我实际上获得了传递给withFunctionNesting的闭包的id (您必须在需要检索当前嵌套的方法中调用该id)。这就是我在实现依赖方错误的地方: id只是函数实例的类。到目前为止,这确实可以正常工作(因为每个一元函数文本都实现为一个实现Function1的类,因此该类充当一个唯一的id),但现实情况是,它很可能在未来的scala版本中中断(尽管不太可能)。所以你要冒着自己的风险去使用它。

最后,我建议您首先认真评估Nikita的建议是否更好的整体解决方案。

票数 4
EN

Stack Overflow用户

发布于 2012-11-07 19:58:46

您可以从函数中返回一个数字,并计算在返回堆栈的过程中所处的级别。但是,没有什么简单的方法可以像您给出的输出示例那样,在下降的过程中进行计算。

票数 0
EN

Stack Overflow用户

发布于 2012-11-07 20:40:56

由于您的问题被标记为"functional“,下面是功能解决方案。当然,程序逻辑完全改变了,但是您的示例代码是必需的。

函数式程序设计的基本原理是没有状态。在命令式编程中,您所拥有的是共享状态,涉及的所有问题(多线程问题等等)都是通过将不变的数据作为函数式编程中的参数传递来实现的。

因此,假设您想传递的“状态”数据是当前循环号,下面是使用递归实现函数的方法:

代码语言:javascript
复制
def decorated ( a : String, cycle : Int ) : String
  = if( cycle <= 0 ) a
    else "I am decorated " + cycle + "x\n" + decorated(a, cycle - 1)

println(decorated("foo", 3))

或者,您可以使您的worker函数非递归并“折叠”它:

代码语言:javascript
复制
def decorated ( a : String, times : Int )
  = "I am decorated " + times + "x\n" + a

println( (1 to 3).foldLeft("foo")(decorated) )

上述两种代码都将产生以下输出:

代码语言:javascript
复制
I am decorated 3x
I am decorated 2x
I am decorated 1x
foo
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13277098

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档