Scalaの区切られた継続に関する研究論文の標準的な例を考えると、への関数入力にshift
名前が付けられ、f
匿名ではなくなるように少し変更されています。
def f(k: Int => Int): Int = k(k(k(7)))
reset(
shift(f) + 1 // replace from here down with `f(k)` and move to `k`
) * 2
Scalaプラグインは、この例を変換して、reset
それぞれshift
からの呼び出し までの(の入力引数内の)計算が、への関数(たとえば)入力にreset
置き換えられるようにします。f
shift
置き換えられた計算は、関数にシフト(つまり移動)されますk
。関数は関数をf
入力しますk
。ここで、置換された計算、入力、および置換の計算がk
含まれます。k
x: Int
k
shift(f)
x
f(k) * 2
def k(x: Int): Int = x + 1
これは次と同じ効果があります:
k(k(k(7))) * 2
def k(x: Int): Int = x + 1
Int
入力パラメーターx
の型(つまり、の型シグニチャーk
)は、の入力パラメーターの型シグニチャーによって指定されていることに注意してくださいf
。
概念的に同等の抽象化を使用した別の借用例、つまり:read
への関数入力です。shift
def read(callback: Byte => Unit): Unit = myCallback = callback
reset {
val byte = "byte"
val byte1 = shift(read) // replace from here with `read(callback)` and move to `callback`
println(byte + "1 = " + byte1)
val byte2 = shift(read) // replace from here with `read(callback)` and move to `callback`
println(byte + "2 = " + byte2)
}
これは、次の論理的等価物に変換されると思います。
val byte = "byte"
read(callback)
def callback(x: Byte): Unit {
val byte1 = x
println(byte + "1 = " + byte1)
read(callback2)
def callback2(x: Byte): Unit {
val byte2 = x
println(byte + "2 = " + byte1)
}
}
これにより、これら2つの例を事前に提示したことで多少わかりにくくなった、一貫性のある共通の抽象化が明らかになることを願っています。たとえば、正規の最初の例は、私の名前ではなく無名関数として研究論文に提示されたため、一部の読者には、借用した2番目の例f
のに抽象的に類似していることがすぐにはわかりませんでした。read
reset
このように区切られた継続は、「あなたは私を外側から呼ぶ」から「私はあなたを内側に呼ぶ」への制御の反転の錯覚を生み出しますreset
。
の戻り型は、の戻り型f
とk
同じである必要がありますが、同じである必要はありません。reset
つまり、と同じ型を返す限り、f
任意の戻り型を宣言する自由があります。との同上(下記も参照)。k
f
reset
read
capture
ENV
区切られた継続は、状態の制御を暗黙的に反転させるものではありません。たとえばread
、callback
純粋関数ではありません。したがって、呼び出し元は参照透過性の式を作成できず、したがって、意図された命令型セマンティクスに対する宣言型(別名透過性)の制御がありません。
継続が区切られた純粋関数を明示的に実現できます。
def aread(env: ENV): Tuple2[Byte,ENV] {
def read(callback: Tuple2[Byte,ENV] => ENV): ENV = env.myCallback(callback)
shift(read)
}
def pure(val env: ENV): ENV {
reset {
val (byte1, env) = aread(env)
val env = env.println("byte1 = " + byte1)
val (byte2, env) = aread(env)
val env = env.println("byte2 = " + byte2)
}
}
これは、次の論理的等価物に変換されると思います。
def read(callback: Tuple2[Byte,ENV] => ENV, env: ENV): ENV =
env.myCallback(callback)
def pure(val env: ENV): ENV {
read(callback,env)
def callback(x: Tuple2[Byte,ENV]): ENV {
val (byte1, env) = x
val env = env.println("byte1 = " + byte1)
read(callback2,env)
def callback2(x: Tuple2[Byte,ENV]): ENV {
val (byte2, env) = x
val env = env.println("byte2 = " + byte2)
}
}
}
明示的な環境のため、これは騒がしくなりつつあります。
正直なところ、ScalaにはHaskellのグローバル型推論がないunit
ため、Haskellのグローバル(Hindley-Milner)型推論のため、状態モナドへの暗黙的なリフティングをサポートできませんでした(明示的な環境を隠すための1つの可能な戦略として)。ダイヤモンドの複数の仮想継承をサポートしていないことに依存します。