Czym są granice kontekstu i widoku Scala?

W prosty sposób, czym są granice kontekstu i widoku i jaka jest różnica między nimi?

Kilka łatwych do naśladowania przykładów też byłoby świetne!

Author: Peter Mortensen, 2010-12-17

1 answers

Myślałem, że to już zostało zadane, ale jeśli tak, to pytanie nie jest widoczne w pasku "powiązane". Oto ona:

Co To jest widok związany?

A view bound był mechanizmem wprowadzonym w Scali w celu umożliwienia użycia pewnego typu A jakby {[59] } to był jakiś typ B. Typowa składnia jest następująca:

def f[A <% B](a: A) = a.bMethod

Innymi słowy, {[14] } powinna mieć dostępną konwersję implicit do B, aby można było wywoływać metody B na obiekcie typu A. Najczęściej używane są ograniczenia widoku w bibliotece standardowej (przed scalią 2.8.0, tak czy inaczej), to Ordered, Jak to:

def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b

Ponieważ można przekształcić A w Ordered[A], a ponieważ Ordered[A] definiuje metodę <(other: A): Boolean, mogę użyć wyrażenia a < b.

Należy pamiętać, że ograniczenia widoku są przestarzałe , należy ich unikać.

Co To jest kontekst związany?

Ograniczenia kontekstu zostały wprowadzone w Scali 2.8.0 i są zazwyczaj używane z tak zwany wzorzec klasy typu , wzorzec kodu, który emuluje funkcjonalność dostarczaną przez klasy typu Haskell, choć w bardziej wyrazisty sposób.

Podczas gdy Wiązanie widoku może być używane z typami prostymi( na przykład A <% String), Wiązanie kontekstu wymaga parametryzowanego typu , takiego jak Ordered[A] powyżej, ale w przeciwieństwie do String.

Context bound opisuje wartość implicit , zamiast implicit konwersji view bound. Służy do deklarowania, że dla pewnego typu A dostępna jest wartość domyślna typu B[A]. Składnia wygląda tak:
def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]

Jest to bardziej mylące niż widok związany, ponieważ nie jest od razu jasne, jak go używać. W Scali często używa się tego słowa:

def f[A : ClassManifest](n: Int) = new Array[A](n)

Inicjalizacja Array na parametryzowanym typie wymaga dostępności ClassManifest, Z tajemnych powodów związanych z usunięciem typu i nieusuwalnym charakterem tablic.

Kolejny bardzo powszechny przykład w Biblioteka jest nieco bardziej złożona:

def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)

Tutaj, implicitly jest używany do pobierania żądanej wartości domyślnej, jednej z typów Ordering[A], której klasa definiuje metodę compare(a: A, b: A): Int.

Zobaczymy inny sposób zrobienia tego poniżej.

Jak zaimplementowane są obramowania widoku i obramowania kontekstu?

Nie powinno dziwić, że zarówno granice widoku, jak i granice kontekstu są implementowane z domyślnymi parametrami, biorąc pod uwagę ich definicję. Właściwie składnia, którą pokazałem, to cukry składniowe dla czego naprawdę się zdarza. Zobacz poniżej, jak odcedzają cukier:

def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod

def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)
Oczywiście, można je zapisać w pełnej składni, która jest szczególnie przydatna dla ograniczeń kontekstu:]}
def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)

Do czego służą granice widoków?

Ograniczenia widoku są używane głównie do wykorzystania wzorcapimp my library , za pomocą którego "dodaje się" metody do istniejącej klasy, w sytuacjach, w których chcesz w jakiś sposób zwrócić oryginalny typ. Jeśli nie musisz zwracać tego typu w jakikolwiek sposób, to nie potrzebujesz widoku związanego.

Klasycznym przykładem użycia view bound jest obsługa Ordered. Zauważ, że Int nie jest Ordered, na przykład, chociaż istnieje konwersja niejawna. Przykład podany wcześniej wymaga przypisania widoku, ponieważ zwraca Nie skonwertowany typ:

def f[A <% Ordered[A]](a: A, b: A): A = if (a < b) a else b

Ten przykład nie będzie działał bez ograniczeń widoku. Jednak, jeśli miałbym zwrócić inny typ, to nie potrzebuję już widoku związanego:

def f[A](a: Ordered[A], b: A): Boolean = a < b

Konwersja tutaj (w razie potrzeby) dzieje się przed I podaj parametr f, więc f nie musi o tym wiedzieć.

Oprócz Ordered, najczęstszym zastosowaniem biblioteki jest obsługa String i Array, które są klasami Javy, tak jakby były kolekcjami Scali. Na przykład:

def f[CC <% Traversable[_]](a: CC, b: CC): CC = if (a.size < b.size) a else b

Jeśli ktoś spróbuje zrobić to bez ograniczeń widoku, zwracanym typem a String będzie a WrappedString (Scala 2.8), podobnie dla Array.

To samo dzieje się, nawet jeśli typ jest używany tylko jako parametr typu zwracanego typ:

def f[A <% Ordered[A]](xs: A*): Seq[A] = xs.toSeq.sorted

Do czego służą granice kontekstu?

Ograniczenia kontekstowe są używane głównie w tym, co stało się znane jako typeclass pattern, jako odniesienie do klas typów Haskella. Zasadniczo ten wzorzec implementuje alternatywę dla dziedziczenia, udostępniając funkcjonalność za pomocą pewnego rodzaju niejawnego wzorca adaptera.

Klasycznym przykładem jest Scala 2.8 Ordering, która zastąpiła Ordered w całej bibliotece Scali. Użycie to:

def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b

Choć Zwykle zobaczysz, że napisane jest tak:

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
    import ord.mkOrderingOps
    if (a < b) a else b
}

, które wykorzystują pewne niejawne konwersje wewnątrz Ordering, które umożliwiają tradycyjny styl operatora. Innym przykładem w Scali 2.8 jest Numeric:

def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)

Bardziej złożonym przykładem jest użycie nowej kolekcji CanBuildFrom, ale jest już bardzo długa odpowiedź na ten temat, więc uniknę tego tutaj. I, jak wspomniano wcześniej, istnieje użycie ClassManifest, które jest wymagane do inicjalizacji nowych tablic bez konkretnych typy.

Kontekst związany ze wzorcem typeklasy jest znacznie bardziej prawdopodobny do użycia przez twoje własne klasy, ponieważ umożliwiają one oddzielenie obaw, podczas gdy ograniczenia widoków można uniknąć w Twoim kodzie przez dobry projekt (jest używany głównie do obejścia cudzego projektu).

Chociaż było to możliwe przez długi czas, Korzystanie z ograniczeń kontekstowych naprawdę zaczęło działać w 2010 roku i jest obecnie w pewnym stopniu spotykane w większości najważniejszych bibliotek i frameworków Scali. Najbardziej ekstremalnym przykładem jego użycia jest biblioteka Scalaz, która wnosi wiele mocy Haskella do Scali. Polecam zapoznanie się z wzorcami typeklasy, aby lepiej zapoznać się ze wszystkimi sposobami, w jakich można go używać.

EDIT

Interesujące pytania:

 440
Author: Daniel C. Sobral,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:15