轨道
/
F#
F#
/
练习
/
情人节
情人节

情人节

学习练习

简介

可区分联合

可区分联合类型表示固定数量的具名事例。可区分联合的每个值都恰好对应其中一个具名事例。

可区分联合使用 type 关键字定义,各个事例之间用竖线(|)分隔:

type Season =
    | Spring
    | Summer
    | Autumn
    | Winter

可区分联合的每个事例都可以选择性地关联数据,不同事例可以关联不同类型的数据。如果所有事例都没有关联数据,那么这种可区分联合就类似于其他语言通常所说的枚举(或 enum)。

type Number =
    | Integer of int
    | Float of float
    | Invalid

要创建某个特定事例的值,可以引用它的名字(例如 Success)。由于事例名本质上就是构造函数,关联的数据可以像普通函数实参一样传入。如果另一个可区分联合定义了同名的事例,就需要使用它的完整名称(例如 Result.Success)。

let byName = Integer 2
let byFullName = Number.Invalid

可区分联合具有结构相等性,也就是说,同一事例且(可选)数据相同的两个值彼此等价。

虽然可以用 if/elif/else 表达式处理可区分联合,但推荐的做法是通过模式匹配,使用标识符模式:

let describe number =
    match number with
    | Integer i -> sprintf "Integer: %d" i
    | Float d  -> sprintf "Float: %f" d
    | Invalid   -> "Invalid"

说明

这个练习里正逢情人节,你和伴侣打算一起做点有意思的事。伴侣有很多想法,现在要你给这些想法评分,好从中挑出一个活动来。

伴侣提出了以下想法:

  • 玩桌游
  • 放松一下
  • 看一场电影
  • 去餐厅
  • 散步

你有六个任务,帮你选出情人节的活动。

1. 定义 Approval

对于伴侣提出的每个想法,你都要从三种选项中选择一个来回应:yes、no 或 maybe。

定义可区分联合Approval,用以下三个用例来表示这些选项:Yes、No 和 Maybe。

2. 定义 Cuisine

伴侣选出了两家可能去的餐厅:一家是 Korean 菜系,另一家是 Turkish 菜系。

定义可区分联合Cuisine,用以下两个用例来表示这两种菜系:Korean 和 Turkish。

3. 定义 Genre

可以选的电影多如牛毛,为了缩小范围,伴侣还列出了它们的类型。

定义可区分联合Genre,用以下用例来表示这些类型:Crime、Horror、Romance 和 Thriller。

4. 定义 Activity

如前所述,伴侣想出了五种不同的活动:玩桌游、放松一下、看电影、去餐厅和散步。

定义可区分联合Activity,用以下用例来表示这些活动类型:

  • BoardGame:没有关联数据。
  • Chill:没有关联数据。
  • Movie:以它的Genre作为关联数据。
  • Restaurant:以它的Cuisine作为关联数据。
  • Walk:以一个int作为关联数据,表示要走的公里数。

5. 给活动评分

终于可以给伴侣的想法评分了。你对伴侣这些想法的感受是这样的:

  • 玩桌游:no。
  • 放松一下:no。
  • 看电影:如果是爱情片,就 yes;否则 no。
  • 去餐厅:如果是 Korean 菜系就 yes,如果是 Turkish 就 maybe。
  • 散步:走路距离少于三公里就 yes;少于五公里就 maybe;否则 no。

实现一个名为rateActivity的函数,它接收一个Activity值,并根据上面的感受返回Approval:

rateActivity (Restaurant Turkish)
// => Maybe
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
F# Exercism

准备好开始 情人节 了吗?

注册 Exercism,借助 18 个概念148 个练习 和真人导师指导,学习并掌握 F#,全部免费。