¿Cómo se pueden implementar varargs? Necesitamos algún mecanismo para señalar el final de la lista de argumentos. Esto puede ser
- un valor terminador especial, o
- La longitud de la lista vararg pasada como parámetro adicional.
Ambos mecanismos se pueden usar en el contexto del curry para implementar varargs, pero la tipificación adecuada se convierte en un problema importante. Supongamos que estamos tratando con una función sum: ...int -> int, excepto que esta función utiliza curry (por lo que en realidad tenemos un tipo más parecido sum: int -> ... -> int -> int, excepto que no sabemos el número de argumentos).
Caso: valor del terminador: Sea endel terminador especial y Tel tipo de sum. Ahora sabemos que se aplica a endla función devuelve: sum: end -> inty que se aplica a un int tenemos otra suma similar a la función: sum: int -> T. Por lo tanto, Tes la unión de estos tipos: T = (end -> int) | (int -> T). Mediante la sustitución T, obtenemos diferentes tipos posibles, tales como end -> int, int -> end -> int, int -> int -> end -> int, etc. Sin embargo, la mayoría de los sistemas de tipo no dan cabida a esos tipos.
Caso: longitud explícita: el primer argumento para una función vararg es el número de varargs. Así sum 0 : int, sum 1 : int -> int, sum 3 : int -> int -> int -> intetc. Esto se apoya en algunos sistemas de tipo y es un ejemplo de tipificación dependiente . En realidad, el número de argumentos sería un parámetro de tipo y no un parámetro normal - no tendría sentido que la aridad de la función que depender de un valor de tiempo de ejecución, s = ((sum (floor (rand 3))) 1) 2es obviamente mal escrito-: Evalúa a cualquiera s = ((sum 0) 1) 2 = (0 1) 2, s = ((sum 1) 1) 2 = 1 2o s = ((sum 2) 1) 2 = 3.
En la práctica, ninguna de estas técnicas debe usarse, ya que son propensas a errores y no tienen un tipo (significativo) en los sistemas de tipos comunes. En su lugar, sólo tiene que pasar una lista de valores como uno Parámetro: sum: [int] -> int.
Sí, es posible que un objeto aparezca como una función y un valor, por ejemplo, en un sistema de tipos con coacciones. Let sumbe a SumObj, que tiene dos coacciones:
coerce: SumObj -> int -> SumObjpermite sumser utilizado como una función, y
coerce: SumObj -> int nos permite extraer el resultado.
Técnicamente, esta es una variación del caso del valor del terminador anterior, con T = SumObj, y coercees un desempaquetador para el tipo. En muchos lenguajes orientados a objetos, esto es trivialmente implementable con sobrecarga del operador, por ejemplo, C ++:
#include <iostream>
using namespace std;
class sum {
int value;
public:
explicit sum() : sum(0) {}
explicit sum(int x) : value(x) {}
sum operator()(int x) const { return sum(value + x); } // function call overload
operator int() const { return value; } // integer cast overload
};
int main() {
int zero = sum();
cout << "zero sum as int: " << zero << '\n';
int someSum = sum(1)(2)(4);
cout << "some sum as int: " << someSum << '\n';
}