Требуется ли "reset" "сдвиг" внутри блока?

Правильно ли, что reset требуется shift внутри блока? Я попробовал и получил следующее:

scala> reset {} 
error: cannot cps-transform expression (): type arguments [Unit,Unit,Nothing]
do not conform to method shiftUnit type parameter bounds [A,B,C >: B]

Это выглядит разумно (поскольку reset блок без shift внутри - это "мертвый код", который никогда не выполняется), но я не понимаю ошибку.

Каково точное значение сообщения об ошибке?

Ответ 1

Я не согласен, что код внутри reset мертв без shift. Фактически reset просто определяет границы продолжения (это потому, что они называются продолжением с разделителями). Код будет мертв, если у вас shift где-то внутри reset и вы не вызываете продолжение функция. Например:

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]