Невозможно создать анонимную реализацию ContextFunction1 в Scala 3

Я пытаюсь создать анонимную реализацию контекстной функции в 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.

Существует ли ContextFunction1 вообще? Я не могу найти его в документах. Интересно, реализована ли эта функция поверх большого количества сахарного синтаксиса.

Luis Miguel Mejía Suárez 25.04.2024 22:26

Можно ли написать это в стиле «inline»/SAM? stackoverflow.com/questions/76822795/…

Gaël J 25.04.2024 22:26

@GaëlJ можешь привести пример?

riccardo.cardin 25.04.2024 22:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
3
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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:

https://github.com/scala/scala3/blob/main/compiler/src/dotty/tools/dotc/core/Definitions.scala#L90-L148

  /** 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.

Сообщение об ошибке могло бы быть лучше. Такие сообщения часто показывались в первые дни существования Дотти, например. для полиморфных функций: Введите лямбда высшего рода

Другие вопросы по теме