Что такое “контекстно-зависимое” в Scala?

Одной из новых возможностей Scala 2.8 являются границы контекста. Что такое контекстно-зависимое и где это полезно?

Конечно, я искал сначала (и нашел, например, это), но я не мог найти действительно ясную и подробную информацию.

108
задан Community 23 May 2017 в 12:32
поделиться

3 ответа

Вы нашли эту статью? В ней рассматривается новая функция контекстной привязки в контексте улучшения массивов.

Обычно параметр типа с контекстной привязкой имеет вид [T: Bound]; он расширяется до параметра простого типа T вместе с неявным параметром типа Bound[T].

Рассмотрим метод tabulate, который формирует массив из результатов применения заданной функции f к диапазону чисел от 0 до заданной длины. До версии Scala 2.7 метод tabulate мог быть записать следующим образом:

def tabulate[T](len: Int, f: Int => T) = {
    val xs = new Array[T](len)
    for (i <- 0 until len) xs(i) = f(i)
    xs
}

В Scala 2.8 это уже невозможно, поскольку для создания правильного представления Array[T] необходима информация о времени выполнения. Необходимо предоставить эту информацию, передав ClassManifest[T] в метод в качестве неявного параметра:

def tabulate[T](len: Int, f: Int => T)(implicit m: ClassManifest[T]) = {
    val xs = new Array[T](len)
    for (i <- 0 until len) xs(i) = f(i)
    xs
}

В качестве сокращенной формы можно использовать context bound для параметра типа T, что дает:

def tabulate[T: ClassManifest](len: Int, f: Int => T) = {
    val xs = new Array[T](len)
    for (i <- 0 until len) xs(i) = f(i)
    xs
}
102
ответ дан 24 November 2019 в 03:26
поделиться

Ответ Роберта касается технических деталей контекстных границ. Я дам вам свое толкование их значения.

В Scala View Bound ( A <% B ) отражает концепцию «можно рассматривать как» (тогда как верхняя граница <: отражает концепцию «является '). Ограничение контекста ( A: C ) говорит, что "имеет" о типе. Вы можете прочитать примеры манифестов: « T имеет манифест ». Пример, связанный с упорядоченным и упорядоченным , иллюстрирует разницу. Метод

def example[T <% Ordered[T]](param: T)

говорит, что параметр можно рассматривать как упорядоченный . Сравните с

def example[T : Ordering](param: T)

, в котором говорится, что параметр имеет связанный порядок .

С точки зрения использования, потребовалось некоторое время для установления соглашений, но ограничения контекста предпочтительнее границ представления ( границы представления теперь не рекомендуются ). Одно из предложений состоит в том, что привязка контекста предпочтительна, когда вам нужно передать неявное определение из одной области в другую без необходимости ссылаться на нее напрямую (это, безусловно, относится к ClassManifest , используемому для создания массива) .

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

138
ответ дан 24 November 2019 в 03:26
поделиться

(Это примечание в скобках. Сначала прочтите и поймите другие ответы.)

Границы контекста фактически обобщают границы представления.

Итак, учитывая этот код, выраженный с помощью View Bound:

scala> implicit def int2str(i: Int): String = i.toString
int2str: (i: Int)String

scala> def f1[T <% String](t: T) = 0
f1: [T](t: T)(implicit evidence$1: (T) => String)Int

Это также может быть выражено с помощью Context Bound с помощью псевдонима типа, представляющего функции от типа F до типа Т .

scala> trait To[T] { type From[F] = F => T }           
defined trait To

scala> def f2[T : To[String]#From](t: T) = 0       
f2: [T](t: T)(implicit evidence$1: (T) => java.lang.String)Int

scala> f2(1)
res1: Int = 0

Ограничение контекста должно использоваться с конструктором типа типа * => * . Однако конструктор типа Function1 имеет вид (*, *) => * . Использование псевдонима типа частично применяет второй параметр типа с типом String , давая конструктор типа правильного типа для использования в качестве привязки контекста.

Существует предложение, позволяющее напрямую выражать частично применяемые типы в Scala без использования псевдонима типа внутри трейта. Затем вы можете написать:

def f3[T : [X](X => String)](t: T) = 0 
38
ответ дан 24 November 2019 в 03:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: