8

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

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函数跟踪trackedInt实例的调用(例如7.tracked)。

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

track(7.tracked + 35.tracked)
4

2 回答 2

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.9.1,前提是您将 2.10.x 隐式值类替换为:

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函数的延续线程化,该函数采用当前状态(整数集)并返回下一个状态。reset 的返回类型是一个从状态到状态(类型为ST)的函数,它将采用初始状态并返回最终状态。

最后一个技巧是使用 var 来捕获结果,同时仍然保持reset.

于 2013-04-10T06:13:13.520 回答
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
......

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

现在,如果您还不满意,您应该知道编译器通过使用以下选项对“树”执行一组转换来工作,您可能会看到这些转换:

  • -Xprint:在某个阶段执行后显示你的 scala 代码
  • -Xprint: -Yshow-trees 显示你的 scala 代码和执行阶段后的树
  • -YBrowse:打开一个 GUI 来浏览两者。
于 2012-07-10T07:41:43.593 回答