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)))
}

tracktracked関数は、Intインスタンス (例: )の呼び出しを追跡します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.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状態は、現在の状態 (int のセット) を取得して次の状態を返す関数を返す継続によってスレッド化されます。STreset の戻り値の型は、初期状態を取り、最終状態を返す(型の) 状態から状態への関数です。

最後のトリックは、var を使用して結果をキャプチャしながら、期待される型を維持することですreset

于 2013-04-10T06:13:13.520 に答える
1

この質問に対する正確な答えは、コンパイラの作成者だけが与えることができますが、継続プラグインのソース コードを見て、それは不可能であると推測できます。

継続のソースを見ると、次のことがわかります。

  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 は selectedAnf の後に実行されます。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 フェーズと selectedCps フェーズの前に適用されます。型推論が typer フェーズで発生することを確認する必要がありますが、これが実際に当てはまり、それが理にかなっている場合、7.tracked と 35.tracked で Int 型を省略できない理由が明確になるはずです。

まだ満足していない場合は、次のオプションを使用して、「ツリー」に一連の変換を実行することでコンパイラが機能することを知っておく必要があります。

  • -Xprint: 特定のフェーズが実行された後の scala コードを表示します
  • -Xprint: -Yshow-trees は、フェーズが実行された後の scala コードとツリーを表示します
  • -YBrowse: 両方をサーフィンするための GUI を開きます。
于 2012-07-10T07:41:43.593 に答える