Как расширить класс functionN в Scala

Я новичок в Scala. У меня есть Class A, extends и Class C. У меня также есть Class B, который также extends и Class C

Я хочу, чтобы функциональные объекты типа A->B также расширяли C (а также другие производные типы, такие как A->(A->B)). Но я прочитал в "Программировании в scala" следующее:

Функциональный литерал компилируется в класс, который при создании экземпляра во время выполнения является значением функции.

Есть ли способ автоматически разрешить A->B extend C, кроме как вручную создать новый класс, представляющий функцию?


person user3068137    schedule 15.01.2018    source источник
comment
К сожалению, я еще не решил проблему. Ваш ответ содержит много новых для меня тем, которые мне сначала нужно прочитать. Кроме того, этот проект является просто побочным проектом, и в последнее время у меня не было много времени для работы над ним. Извини!   -  person user3068137    schedule 01.02.2018
comment
Ничего страшного, лишь бы помогло.   -  person slouc    schedule 19.06.2018


Ответы (1)


Функции в Scala моделируются через трейт FunctionN. Например, все простые функции с одним входом и одним выходом являются экземплярами следующего признака:

trait Function1[-T1, +R] extends AnyRef

Итак, вы спрашиваете: «Как я могу сделать экземпляры Function также подклассами C». Это невозможно сделать с помощью стандартного подтипа/наследования, потому что, очевидно, мы не можем изменить черту Function1, чтобы она расширяла ваш пользовательский класс C. Конечно, мы могли бы создать новый класс для представления функции, как вы предложили, но это только заведет нас так далеко, и это не так просто реализовать, не говоря уже о том, что любую функцию, которую вы хотите использовать как C, придется преобразовать. сначала к вашей псевдофункциональной черте, что сделает все ужасно.

Что мы можем сделать, так это создать класс типов, который затем будет содержать реализацию для A -> B, среди прочего.

В качестве примера возьмем следующий код:

trait A
trait B
trait C[T]

object C {
  implicit val fa = new C[A] {}
  implicit val fb = new C[B] {}
  implicit val fab = new C[Function1[A, B]] {}
}


object Test extends scala.App {

  val f: A => B = (a: A) => new B {}

  def someMethod[Something: C](s: Something) = {
    // uses "s", for example:
    println(s)
  }

  someMethod(f) // Test$$$Lambda$6/1744347043@dfd3711

}

Вы не указали свою мотивацию для того, чтобы сделать A -> B расширением C, но, очевидно, вы хотите иметь возможность поместить A, B и A -> B под «одним и тем же зонтиком», потому что у вас есть, скажем, некоторый метод (называемый someMethod ), который принимает C, поэтому при наследовании вы можете передавать ему значения типа A, B или A -> B.

С классом типов вы достигаете того же самого, но с некоторыми дополнительными преимуществами, такими как, например. добавление D в семейство в один прекрасный день без изменения существующего кода (вам просто нужно реализовать неявное значение типа C[D] где-то в области видимости).

Таким образом, вместо того, чтобы someMethod принимал экземпляры C, он просто берет что-то (назовем это s) некоторого типа (назовем это Something) с ограничением, что C[Something] должно существовать. Если вы передадите что-то, для чего не существует экземпляра C, вы получите сообщение об ошибке:

trait NotC
someMethod(new NotC {}) 
// Error: could not find implicit value for evidence parameter of type C[NotC]

Вы достигаете того же самого — у вас есть семья из C, членами которой являются A, B и A => B, но вы обходите проблемы с подтипами.

person slouc    schedule 15.01.2018
comment
Мне удалось получить первую рабочую версию с этим, спасибо. У меня все еще есть некоторые вопросы по этому поводу: - person user3068137; 03.09.2018
comment
@ user3068137 Какие вопросы? - person slouc; 03.09.2018
comment
Я разместил их как ответ, потому что он превысил максимальное количество символов для комментария. Но теперь этот ответ был удален. Что я должен делать? - person user3068137; 04.09.2018
comment
Какой тип возвращает метод someMethod? Я хотел бы вызвать someMethod несколько раз, чтобы получить значения и сохранить их в наборе. Но тогда этот набор будет содержать элементы разных типов, всех видов, которые расширяют C, например A, B, A->B и A->(A->B). Как я могу это сделать? - person user3068137; 05.09.2018
comment
Он будет содержать элементы типа some T, для которых Something[T] существует. Тип возврата someMethod() в этом примере — это просто Unit, потому что он просто выводит элемент. - person slouc; 05.09.2018
comment
Я хотел сказать: если я хочу, чтобы метод someMethod возвращал s типа Something, как мне написать возвращаемый тип. Потому что, если я использую Something в качестве типа возвращаемого значения и пытаюсь присвоить его значению, я получаю сообщение об ошибке, что типы не соответствуют. Я хочу извлечь значение (которое относится к типу A, типу B или типу A->B) с помощью этого метода someMethod, но я не могу заставить его работать. - person user3068137; 05.09.2018