轨道
/
Gleam
Gleam
/
练习
/
贴纸商店
贴纸商店

贴纸商店

学习练习

简介

幻影类型

幻影类型是自定义类型的类型参数,它们不会在该类型的任何值构造器中使用。

这有点抽象,来看一个例子:

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值,那么我们就可以确保不会用无效的单位类型来构造它们,并确保只有上面定义的函数才能与它们一起使用。

说明

Lucy 开了一家在线贴纸店,卖各种可爱的贴纸,贴纸上印着大家最喜欢的编程语言。世界各地的人都来买她的贴纸,而她在应付各种不同货币时遇到了一些麻烦。

编写一个程序,让 Lucy 用它来计算价格,同时确保她始终使用的是正确的货币。

1. 定义Usd、Eur和Jpy类型

这些类型用于表示 Lucy 的顾客购买贴纸时使用的不同货币。

它们用作幻影类型,不需要有任何构造函数。

2. 定义Money类型

Money类型应该有一个用于表示金额的Int字段、一个货币幻影类型参数,并且是不透明类型。

3. 定义dollar、euro和yen函数

定义dollar、euro和yen函数,它们接收一个Int实参,并返回一个带正确货币的Money值。

4. 定义total函数

定义total函数,它接收一个由Money值组成的数组,并返回数组中金额的总和。

total([euro(120), euro(200), euro(145)])
// -> euro(465)
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Gleam Exercism

准备好开始 贴纸商店 了吗?

注册 Exercism,借助 33 个概念122 个练习 和真人导师指导,学习并掌握 Gleam,全部免费。