Los tipos fantasma son parámetros de tipo de un tipo personalizado que no se utilizan en ninguno de los constructores de valor de ese tipo.
Esto es un poco abstracto, así que aquí tienes un ejemplo:
pub type Length(unit) {
Length(amount: Float)
}
En este ejemplo, el parámetro de tipo unit no se utiliza en el constructor de valor Length, así que unit es un tipo fantasma.
Este parámetro de tipo sin usar puede parecer inútil, pero se puede utilizar para añadir más restricciones sobre cómo se pueden usar los valores Length.
Por ejemplo, podríamos tener una función double, que multiplica la longitud. Funciona con longitudes de cualquier unidad, así que el parámetro de tipo es una variable de tipo genérica.
// This function accepts all Length values
pub fn double(length: Length(unit)) -> Length(unit) {
Length(length.amount *. 2.0)
}
También podríamos tener una función add_inch, que solo funciona si la longitud está en pulgadas.
// A unit type for inches. It is never constructed so we don't
// define any constructors for it.
pub type Inches
pub fn add_inch(length: Length(Inches)) -> Length(Inches) {
Length(length.amount +. 1.0)
}
La función add_inch no aceptará longitudes cuyo parámetro de tipo sea otra unidad, el tipo fantasma se ha utilizado para asegurar que solo se use la unidad correcta.
También se puede escribir una función para asegurar que dos valores de longitud sean de la misma unidad, utilizando la misma variable de tipo para ambos.
pub fn add(a: Length(unit), b: Length(unit)) -> Length(unit) {
Length(a.amount +. b.amount)
}
let two_meters: Length(Meters) = Length(2.0)
let two_inches: Length(Inches) = Length(2.0)
add(two_meters, two_meters)
// -> Length(4.0): Length(Meters)
add(two_meters, two_inches)
// Type error! The unit type parameters do not match.
Los tipos fantasma pueden funcionar bien con tipos opacos. Si otros módulos no pueden construir valores Length, entonces podemos asegurarnos de que no se construyan con un tipo de unidad no válido, y de que solo se puedan usar con ellos las funciones definidas anteriormente.
Lucy tiene una tienda de pegatinas en línea, donde vende pegatinas monas con los lenguajes de programación favoritos de todo el mundo. Personas de todo el mundo compran sus pegatinas, y está teniendo problemas para lidiar con todas las distintas monedas.
Crea un programa que Lucy pueda usar para calcular precios y asegurarse de que siempre usa la moneda correcta.
Usd, Eur y Jpy
Estos tipos se usan para representar las distintas monedas que los clientes de Lucy usan para comprar sus pegatinas.
Deben usarse como tipos fantasma y no necesitan tener ningún constructor.
Money.El tipo Money debe tener un campo Int para la cantidad de dinero, un parámetro de tipo fantasma de moneda, y debe ser un tipo opaco.
dollar, euro y yen
Define las funciones dollar, euro y yen, que reciben un argumento Int y devuelven un valor Money con la moneda correcta.
total
Define la función total, que recibe un array de valores Money y devuelve la cantidad total de dinero del array.
total([euro(120), euro(200), euro(145)])
// -> euro(465)
Regístrate en Exercism para aprender y dominar Gleam con 33 conceptos122 ejercicios y mentoría humana real, todo gratis.