Я пытаюсь создать анонимную реализацию контекстной функции в Scala 3. Подробно код выглядит следующим образом:
def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = new ContextFunction1[Raise[E], A] {
override def apply(using r: Raise[E]): A = block(using r)
}
Однако, если я попытаюсь скомпилировать его, компилятор выдаст мне следующую ошибку:
[error] 213 |}
[error] | ^
[error] | Found: Object with ((in.rcard.raise4s.Raise[E]) ?=> A) {...}
[error] | Required: A
Ошибки не будет, если перейду на классику Function1.
Можно ли написать это в стиле «inline»/SAM? stackoverflow.com/questions/76822795/…
@GaëlJ можешь привести пример?





ContextFunction1 не является частью Scala API https://docs.scala-lang.org/api/all.html , поэтому его не следует использовать в исходном коде вручную, хотя это описано по адресу https:// docs.scala-lang.org/scala3/reference/contextual/context-functions-spec.html
Даже обычные функции обычно создаются с помощью лямбда-синтаксиса, а не ключевого слова new. new Function1 компилируется в invokespecial, а ... => ... компилируется в invokedynamic байт-код.
Определите неявные функции через ?=> (как на уровне типа, так и на уровне значения):
def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = (r: Raise[E]) ?=> block(using r)
def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = r ?=> block(using r)
def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = _ ?=> block
def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = block
В компиляторе здесь создаются символы ContextFunctionN:
/** The trait FunctionN and ContextFunctionN for some N
* @param name The name of the trait to be created
*
* FunctionN traits follow this template:
*
* trait FunctionN[-T0,...-T{N-1}, +R] extends Object {
* def apply($x0: T0, ..., $x{N_1}: T{N-1}): R
* }
*
* That is, they follow the template given for Function2..Function22 in the
* standard library, but without `tupled` and `curried` methods and without
* a `toString`.
*
* ContextFunctionN traits follow this template:
*
* trait ContextFunctionN[-T0,...,-T{N-1}, +R] extends Object {
* def apply(using $x0: T0, ..., $x{N_1}: T{N-1}): R
* }
* ImpureXYZFunctionN follow this template:
*
* type ImpureXYZFunctionN[-T0,...,-T{N-1}, +R] = {cap} XYZFunctionN[T0,...,T{N-1}, R]
*/
private def newFunctionNType(name: TypeName): Symbol = {
...
Неспособность создать экземпляр ContextFunction1 кажется ожидаемым поведением
// `ContextFunctionN` does not have constructors
!ctor.exists || zeroParams(ctor.info)
https://github.com/scala/scala3/blob/main/compiler/src/dotty/tools/dotc/core/Types.scala#L6011
/** ... check that ... no user-written class extends ContextFunctionN.
*/
def checkParents(cls: Symbol, parentTrees: List[Tree])(using Context): Unit = cls.info match {
...
https://github.com/scala/scala3/blob/main/compiler/src/dotty/tools/dotc/typer/RefChecks.scala#L120
Для FunctionN исходники генерируются для стандартной библиотеки Scala 2 (также используется в Scala 3). Для ContextFunctionN исходники даже не генерируются.
Во время выполнения ContextFunctionN не существует (Class.forName("scala.ContextFunction1") выбрасывает ClassNotFoundException). ContextFunctionN стираются до FunctionN.
Сообщение об ошибке могло бы быть лучше. Такие сообщения часто показывались в первые дни существования Дотти, например. для полиморфных функций: Введите лямбда высшего рода
Существует ли
ContextFunction1вообще? Я не могу найти его в документах. Интересно, реализована ли эта функция поверх большого количества сахарного синтаксиса.