【问题标题】:Does "reset" require "shift" inside the block?“重置”是否需要在块内“移位”?
【发布时间】:2011-08-25 20:01:14
【问题描述】:

reset 在块内需要shift 是否正确?我试了一下,得到了以下结果:

scala> 重置 {}
错误:无法 cps 转换表达式 ():类型参数 [Unit,Unit,Nothing]
不符合方法 shiftUnit 的类型参数界限 [A,B,C >: B]

看起来很合理(因为内部没有shiftreset 块是“死代码”,永远不会执行)但我不明白这个错误。

错误信息的确切含义是什么?

【问题讨论】:

    标签: scala continuations


    【解决方案1】:

    我不同意,reset 中的代码没有shift 就死了。实际上 reset 只是定义了延续的边界(那是因为它们被称为 delimited 延续)。如果你在 reset 中的某个地方有 shift 并且你不调用延续,那么代码就会死掉功能。例如:

    reset {
      println(1)
      shift((k: Unit => Unit) => println(2))
      println(3)
    }
    

    shift 后面的代码已经死掉了(println(3)),因为我还没有调用k(Unit)

    另一方面,reset 似乎期望从它的主体中获得一些特殊的返回类型 - 使用 @cpsParam 注释进行注释的返回类型。你可以查看reset方法的定义:

    def reset[A,C](ctx: => (A @cpsParam[A,C])): C = ...
    

    shift 产生的正是reset 方法所期望的。这是shift方法的定义:

    def shift[A,B,C](fun: (A => B) => C): A @cpsParam[B,C] = ...
    

    但您仍然可以使用 reset 而无需在其中调用 shift。这个技巧可以做到:

    def foo[T](body: => T @cps[Any]) = reset(body)
    
    foo {
      println("it works")
    }
    

    请注意,@cps 只是 @cpsParam 的类型别名。这是定义:

    type cps[A] = cpsParam[A, A]
    

    【讨论】:

      猜你喜欢
      • 2011-09-05
      • 2019-03-12
      • 1970-01-01
      • 1970-01-01
      • 2012-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多