Что такое "контекстная привязка" в Scala?



одной из новых функций Scala 2.8 являются контекстные границы. Что такое контекстная привязка и где она полезна?



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

542   4  

4 ответов:

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

как правило, параметр Type С контекстно-привязанных имеет форму [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
}

как сокращенная форма, a контекстно-привязанных можно использовать для параметра типа , дача:

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
}

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

в Scala вид привязан (A <% B) захватывает понятие "может рассматриваться как" (в то время как верхняя граница <: захватывает понятие 'is a'). Контекст привязан (A : C) говорит "имеет" о типе. Вы можете прочитать примеры о манифестах как"T есть Manifest". Пример, который вы связали с about Ordered vs Ordering иллюстрирует разницу. Один метод

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

говорит, что параметр можно рассматривать как Ordered. Сравните с

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

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

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

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

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

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

Итак, учитывая этот код, выраженный с привязкой вида:

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: (T) => String)Int

это также может быть выражено с привязкой к контексту, с помощью псевдонима типа, представляющего функции из типа F типа T.

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: (T) => java.lang.String)Int

scala> f2(1)
res1: Int = 0

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

есть предложение разрешить вам напрямую выражать частично применяемые типы в Scala, без использования псевдонима типа внутри признака. Тогда вы могли бы написать:

def f3[T : [X](X => String)](t: T) = 0 

это еще одно примечание в скобках.

как Бен указал, контекстная привязка представляет собой ограничение" has-a " между параметром типа и классом типа. Другими словами, он представляет собой ограничение, что неявное значение определенного класса типа существует.

при использовании привязки к контексту часто требуется отобразить это неявное значение. Например, учитывая ограничение T : Ordering, часто требуется экземпляр Ordering[T] это удовлетворяет ограничению. как показано ниже, можно получить доступ к неявному значению с помощью implicitly метод или немного более полезным context способ:

def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) = 
   xs zip ys map { t => implicitly[Numeric[T]].times(t._1, t._2) }

или

def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) =
   xs zip ys map { t => context[T]().times(t._1, t._2) }

Comments

    Ничего не найдено.