Фантомні типи - це параметри типу, оголошені у власному типі, але не використані в жодному з його конструкторів значень.
Це трохи абстрактно, тож ось приклад:
pub type Length(unit) {
Length(amount: Float)
}
У цьому прикладі параметр типу unit не використовується в конструкторі значень Length, тож unit - фантомний тип.
Цей невикористаний параметр типу може здатися непотрібним, але він дає змогу накласти додаткові обмеження на те, як можна використовувати значення Length.
Наприклад, у нас могла б бути функція double, яка множить довжину. Вона працює з довжинами будь-якої одиниці, тож параметр типу - це узагальнена змінна типу.
// This function accepts all Length values
pub fn double(length: Length(unit)) -> Length(unit) {
Length(length.amount *. 2.0)
}
Також у нас могла б бути функція add_inch, яка працює лише тоді, коли довжина вимірюється в дюймах.
// 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)
}
Функція add_inch не прийматиме довжини з будь-яким іншим параметром одиниці: фантомний тип використано, щоб гарантувати, що застосовується лише правильна одиниця.
Можна також написати функцію, яка гарантує, що два значення довжини мають ту саму одиницю, використавши для обох ту саму змінну типу.
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.
Фантомні типи добре працюють разом із непрозорими типами. Якщо інші модулі не можуть створити значення Length, ми можемо гарантувати, що їх не буде створено з недійсним типом одиниці, і що з ними можна буде використовувати лише функції, визначені вище.
У Люсі є онлайн-магазин наліпок, де вона продає милі наліпки із зображеннями улюблених мов програмування. Люди з усього світу купують її наліпки, і їй непросто давати раду всім різним валютам.
Створіть програму, яку Люсі зможе використовувати для обчислення цін і при цьому бути впевненою, що завжди використовує правильну валюту.
Usd, Eur і Jpy
Ці типи позначають різні валюти, якими покупці Люсі платять за її наліпки.
Їх слід використовувати як фантомні типи, і вони не потребують жодних конструкторів.
Money.Тип Money повинен мати поле Int для суми грошей, фантомний параметр типу валюти, і має бути непрозорим типом.
dollar, euro і yen
Визначте функції dollar, euro і yen, які приймають аргумент Int і повертають значення Money з правильною валютою.
total
Визначте функцію total, яка приймає масив значень Money і повертає загальну суму грошей у масиві.
total([euro(120), euro(200), euro(145)])
// -> euro(465)
Зареєструйтеся на Exercism, щоб вивчати й опановувати Gleam, а також 33 концепції122 вправи та справжнє наставництво від людей, і все це безкоштовно.