轨道
/
Haskell
Haskell
/
练习
/
情人节
情人节

情人节

学习练习

简介

代数数据类型(ADT)表示固定数量的具名情况,ADT 的每个值都恰好对应其中一个情况。

ADT 用data关键字定义,各个情况之间用竖线(|)分隔。如果所有情况都没有关联数据,这种 ADT 就类似其他语言通常所说的_枚举_(或 enum)。

data Season
  = Spring
  | Summer
  | Autumn
  | Winter

ADT 的每个情况都可以选择性地关联数据,不同情况关联的数据类型也可以不同。情况关联了数据时,就必须使用构造函数。

data Number
  = NInt Int      --'NInt' is the constructor for an Int Number.
  | NFloat Float  --'NFloat' is the constructor for an Float Number.
  | Invalid       --'Invalid' does not have data associated to it.

要为某个特定情况创建值,只需引用它的名字(例如 NInt 22)。情况名本身就是构造函数,因此关联的数据可以像普通的函数实参一样传入。

ADT 具有_结构相等性_,也就是说,属于同一情况、且(可选的)数据也相同的两个值彼此等价。

虽然可以用if/else表达式来处理 ADT,但推荐的做法是使用模式匹配,也就是 case 语句:

add1 :: Number -> String
add1 number =
    case number of
      NInt    i -> show (i + 1)
      NFloat  f -> show (f + 1.0)
      Invalid   -> error "Invalid input"

说明

在这个练习中,今天是情人节,你正在计划和伴侣一起做什么。你的伴侣有很多想法,并让你给这些想法打分,以便找出最好的活动。

以下是你的伴侣提出的想法:

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

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

1. 定义 approval

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

定义Approval代数数据类型,用下面三种情况来表示这些选项:Yes、No或Maybe。

2. 定义 cuisines

你的伴侣选了两家可能的餐厅:一家做韩式料理,另一家做土耳其料理。

定义Cuisine代数数据类型,用下面两种情况来表示这两家餐厅:Korean或Turkish。

3. 定义电影类型

可供选择的电影太多了,为了缩小范围,你的伴侣还列出了自己偏好的电影类型。

定义Genre代数数据类型,来表示以下几种类型:Crime、Horror、Romance或Thriller。

4. 定义活动

正如前面提到的,你的伴侣想出了五种可能的活动:玩桌游、放松一下、看电影、去餐厅吃饭和散步。

定义Activity代数数据类型来表示这些活动类型:

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

5. 给活动打分

最后,你可以给伴侣的想法打分了。以下是你对伴侣想法的感受:

  • 玩桌游:no。
  • 放松一下:no。
  • 看电影:如果是爱情片,就是 yes;否则是 no。
  • 去餐厅吃饭:如果是韩式料理,就是 yes;如果是土耳其料理,就是 maybe。
  • 散步:如果不到 3 公里,就是 yes;如果在 3 到 5 公里之间(含 3 公里和 5 公里),就是 maybe;否则是 no。

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

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

准备好开始 情人节 了吗?

注册 Exercism,借助 107 个练习 和真人导师指导,学习并掌握 Haskell,全部免费。