在continuation中推断结果类型

时间:2012-05-28 07:44:33

标签: scala type-inference continuations

是否可以从以下代码中删除某些类型:

import util.continuations._

object TrackingTest extends App {

  implicit def trackable(x: Int) = new {
    def tracked[R] = shift { cf: (Int => (R, Set[Int])) =>
      cf(x) match {
        case (r, ints) => (r, ints + x)
      }
    }
  }


  def track[R](body: => R @cpsParam[(R, Set[Int]), (R, Set[Int])]) = reset {
    (body, Set[Int]())
  }

  val result = track(7.tracked[Int] + 35.tracked[Int])
  assert(result == (42, Set(7, 35)))

  val differentTypes = track(9.tracked[String].toString)
  assert(differentTypes == ("9", Set(9)))
}

track功能会跟踪tracked个实例Int的来电(例如7.tracked)。

是否可以在tracked隐式推断类型参数,因此以下内容将编译:

track(7.tracked + 35.tracked)

2 个答案:

答案 0 :(得分:2)

你的问题让我想到了延续如何追踪状态。所以我根据你的情况调整了这个并提出了这个:

import util.continuations._

object TrackingTest extends App {

  type State = Set[Int]
  type ST = State => State

  implicit class Tracked(val i: Int) extends AnyVal { 
    def tracked = shift{ (k: Int=>ST) => (state:State) => k(i)(state + i) }
  }

  def track[A](thunk: => A@cps[ST]): (A, State) = {
    var result: A = null.asInstanceOf[A]
    val finalSate = (reset {
      result = thunk
      (state:State) => state
    }).apply(Set[Int]())
    (result, finalSate)
  }

  val result = track(7.tracked + 35.tracked)
  assert(result == (42, Set(7, 35)))

  val differentTypes = track(9.tracked.toString)
  assert(differentTypes == ("9", Set(9)))
}

这是使用2.10.1,但如果用以下内容替换2.10.x隐式值类,它也适用于2.9.1

implicit def tracked(i: Int) = new {
  def tracked = shift{ (k: Int=>ST) => (state:State) => k(i)(state + i) }
}

我做的主要更改是让tracked不使用任何类型推断,修复为Int@cps[ST]。然后,CPS插件会根据需要将计算映射到正确的类型(如String@cps[ST])。状态由继续返回一个State=>State函数,该函数接受当前状态(一组整数)并返回下一个状态。复位的返回类型是一个从状态到状态(类型为ST)的函数,它将采用初始状态并返回最终状态。

最后一招是使用var来捕获结果,同时保持reset的预期类型。

答案 1 :(得分:1)

虽然这个问题的确切答案只能由编译器的作者给出,但我们可以通过查看continuation插件源代码来猜测它是不可能的。

如果您查看延续的来源,可以看到:

  val anfPhase = new SelectiveANFTransform() {
    val global = SelectiveCPSPlugin.this.global
    val runsAfter = List("pickler")
  }

  val cpsPhase = new SelectiveCPSTransform() {
    val global = SelectiveCPSPlugin.this.global
    val runsAfter = List("selectiveanf")
  }

anfPhase阶段在pickler阶段之后执行,而cpsPhase在selectiveAnf之后执行。如果你看SelectiveANFTransform.scala

abstract class SelectiveANFTransform extends PluginComponent with Transform with
  TypingTransformers with CPSUtils {
  // inherits abstract value `global' and class `Phase' from Transform

  import global._                  // the global environment
  import definitions._             // standard classes and methods
  import typer.atOwner             // methods to type trees

  /** the following two members override abstract members in Transform */
  val phaseName: String = "selectiveanf"

如果我们使用scalac -Xshow-phases,我们可以看到编译过程中的阶段:

parser
namer
packageobjects
typer
superaccessors
pickler
refchecks
selectiveanf
liftcode
selectivecps
uncurry
......

正如您所看到的,在selectiveAnf和selectiveCps阶段之前应用了typer阶段。应该确认类型推断发生在typer阶段,但如果确实如此并且它是有意义的,现在应该清楚为什么你不能省略7.tracked和35.tracked上的Int类型。 / p>

现在,如果您还不满意,您应该知道编译器是通过使用以下选项对“树”执行一组转换来实现的:

  • -Xprint:在执行某个阶段后显示您的scala代码
  • -Xprint:-Yshow-trees显示您的scala代码和执行阶段后的树
  • -YBrowse:打开一个GUI浏览两者。