I tipi fantasma sono parametri di tipo di un tipo personalizzato che non vengono usati in nessuno dei costruttori di valore di quel tipo.
È un po' astratto, quindi ecco un esempio:
pub type Length(unit) {
Length(amount: Float)
}
In questo esempio il parametro di tipo unit non viene usato nel costruttore di valore Length, quindi unit è un tipo fantasma.
Questo parametro di tipo inutilizzato può sembrare inutile, ma può servire ad aggiungere ulteriori restrizioni su come si possono usare i valori di Length.
Per esempio, potremmo avere una funzione double, che moltiplica la lunghezza. Funziona con lunghezze di qualsiasi unità, quindi il parametro di tipo è una variabile di tipo generica.
// This function accepts all Length values
pub fn double(length: Length(unit)) -> Length(unit) {
Length(length.amount *. 2.0)
}
Potremmo anche avere una funzione add_inch, che funziona solo se la lunghezza è in pollici.
// 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 funzione add_inch non accetterà lunghezze con qualsiasi altro parametro di unità: il tipo fantasma è stato usato per garantire che venga usata solo l'unità corretta.
Si può anche scrivere una funzione che garantisca che due valori di lunghezza abbiano la stessa unità, usando la stessa variabile di tipo per entrambi.
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.
I tipi fantasma funzionano bene insieme ai tipi opachi. Se altri moduli non possono costruire valori di Length, allora possiamo garantire che non vengano costruiti con un tipo di unità non valido, e che con essi si possano usare solo le funzioni definite sopra.
Lucy ha un negozio di adesivi online, dove vende adesivi carini che ritraggono i linguaggi di programmazione preferiti da tutti. Persone da tutto il mondo comprano i suoi adesivi e lei ha qualche difficoltà a gestire tutte le valute diverse.
Crea un programma che Lucy possa usare per calcolare i prezzi, avendo la certezza di usare sempre la valuta corretta.
Usd, Eur e Jpy
Questi tipi servono a rappresentare le diverse valute che i clienti di Lucy usano per comprare i suoi adesivi.
Vanno usati come tipi fantasma e non devono avere alcun costruttore.
Money.Il tipo Money dovrebbe avere un campo Int per la quantità di denaro, un parametro di tipo fantasma per la valuta ed essere un tipo opaco.
dollar, euro e yen
Definisci le funzioni dollar, euro e yen che accettano un argomento Int e restituiscono un valore Money con la valuta corretta.
total
Definisci la funzione total che prende un array di valori Money e ne restituisce l'importo totale.
total([euro(120), euro(200), euro(145)])
// -> euro(465)
Iscriviti a Exercism per imparare e padroneggiare Gleam con 33 concetti122 esercizi e il mentoring di persone reali, tutto gratis.