language-agnostic generics programming-languages partial-specialization

language agnostic - ¿Cuáles son algunos otros lenguajes que apoyan la "especialización parcial"?



language-agnostic generics (6)

La especialización de plantilla parcial es uno de los conceptos más importantes para la programación genérica en C ++. Por ejemplo: para implementar una función de intercambio genérica:

template <typename T> void swap(T &x, T &y) { const T tmp = x; y = x; x = tmp; }

Para especializarlo para que un vector sea compatible con O (1) swap:

template <typename T, class Alloc> void swap(vector<T, Alloc> &x, vector<T, Alloc> &y) { x.swap(y); }

Por lo tanto, siempre puede obtener un rendimiento óptimo cuando llama a swap (x, y) en una función genérica;

Muy apreciado, si puede publicar el equivalente (o el ejemplo canónico de especialización parcial del idioma si el idioma no admite el concepto de intercambio) en idiomas alternativos.

EDITAR : por lo que parece que muchas personas que respondieron / comentaron realmente no sabían qué es la especialización parcial, y que el ejemplo genérico de intercambio parece interferir en la comprensión de algunas personas. Un ejemplo más general sería:

template <typename T> void foo(T x) { generic_foo(x); }

Una especialización parcial sería:

template <typename T> void foo(vector<T> x) { partially_specialized_algo_for_vector(x); }

Una especialización completa sería:

void foo(vector<bool> bitmap) { special_algo_for_bitmap(bitmap); }

¿Por qué esto es importante? porque puedes llamar a foo (cualquier cosa) en una función genérica:

template <typename T> void bar(T x) { // stuff... foo(x); // more stuff... }

y obtenga la implementación más adecuada en tiempo de compilación. Esta es una forma de que C ++ logre la abstracción con una mínima penalización de rendimiento.

Espero que ayude a aclarar el concepto de "especialización parcial". En cierto modo, así es como C ++ escribe la coincidencia de patrones sin necesidad de la sintaxis de concordancia explícita de patrones (por ejemplo, la palabra clave de concordancia en Ocaml / F #), que a veces se interpone en el camino para la programación genérica.


DO#:

void Swap<T>(ref T a, ref T b) { var c = a; a = b; b = c; }

Supongo que la versión (pura) de Haskell sería:

swap :: a -> b -> (b,a) swap a b = (b, a)


En realidad, puedes (no del todo, ver abajo) hacerlo en C # con métodos de extensión:

public Count (this IEnumerable<T> seq) { int n = 0; foreach (T t in seq) n++; return n; } public Count (this T[] arr) { return arr.Length; }

Luego, llamar a array.Count() usará la versión especializada. "No del todo" se debe a que la resolución depende del tipo de array estática, no del tipo de tiempo de ejecución. Es decir, usará la versión más general:

IEnumerable<int> array = SomethingThatReturnsAnArray(); return array.Count();


Haskell tiene instancias superpuestas como una extensión:

class Sizable a where size :: a -> Int instance Collection c => Sizable c where size = length . toList

es una función para encontrar el tamaño de cualquier colección, que puede tener instancias más específicas:

instance Sizable (Seq a) where size = Seq.length

Ver también Advanced Overlap en HaskellWiki .


Java tiene genéricos, que te permiten hacer tipos similares de cosas.


Me temo que C # no admite la especialización de plantillas parciales.

La especialización parcial de la plantilla significa:

Tienes una clase base con dos o más plantillas (genéricos / parámetros de tipo). Los parámetros de tipo serían <T, S>

En una clase derivada (especializada), indica el tipo de uno de los parámetros de tipo. Los parámetros de tipo podrían verse así <T, int>.

Entonces, cuando alguien usa (crea un objeto de) la clase donde el último parámetro de tipo es un int, se usa la clase derivada.


D admite especialización parcial:

(busque "parcial" en los enlaces anteriores).

El segundo enlace en particular le dará un desglose muy detallado de lo que puede hacer con la especialización de plantillas, no solo en D sino también en C ++.

Aquí hay un ejemplo específico de D de swap . Debe imprimir el mensaje para el intercambio especializado para la clase Thing .

import std.stdio; // for writefln // Class with swap method class Thing(T) { public: this(T thing) { this.thing = thing; } // Implementation is the same as generic swap, but it will be called instead. void swap(Thing that) { const T tmp = this.thing; this.thing = that.thing; that.thing = tmp; } public: T thing; } // Swap generic function void swap(T)(ref T lhs, ref T rhs) { writefln("Generic swap."); const T tmp = lhs; lhs = rhs; rhs = tmp; } void swap(T : Thing!(U))(ref T lhs, ref T rhs) { writefln("Specialized swap method for Things."); lhs.swap(rhs); } // Test case int main() { auto v1 = new Thing!(int)(10); auto v2 = new Thing!(int)(20); assert (v1.thing == 10); assert (v2.thing == 20); swap(v1, v2); assert (v1.thing == 20); assert (v2.thing == 10); return 0; }