递归数据类型的其他情况
Additional case for a recursive data type
我目前正在学习 Haskell,我想为货币 Dollar
(只是钞票,不是硬币)定义我自己的递归数据类型。
我的尝试是这样的:
data Dollar = One Dollar
| Two Dollar
| Five Dollar
| Ten Dollar
| Twenty Dollar
| Fifty Dollar
| Hundred Dollar
我把这个给我的一个朋友看了,他说看起来不错,但他还告诉我在定义的末尾加上一个 | End
。他试图解释为什么有必要,但我无法理解他的思路。也许这里有人有我可以遵循的解释。非常感谢。
您的朋友可能表示在某些时候您需要一个基本案例。给定定义
data Dollar = One Dollar
| Two Dollar
| Five Dollar
| Ten Dollar
| Twenty Dollar
| Fifty Dollar
| Hundred Dollar
| End
您可以将任意数量的钱表示为 Dollar
值的链表,每个值代表一张账单和“剩余”的钱。 End
将终止列表。例如,
fortyTwoDollars :: Dollar
fortyTwoDollars = Twenty (Ten (Five (Five (Two End))))
但是,我看不出有什么理由将列表混入其中;单个 Dollar
值可以单独表示一张账单,您可以使用 [Dollar]
值表示一个集合。
data Dollar = One
| Two
| Five
| Ten
| Twenty
| Fifty
| Hundred
fortyTwoDollars :: [Dollar]
fortyTwoDollars = [Twenty, Ten, Five, Five, Two]
这个不需要递归
描述账单的问题不需要递归类型。让我们从一个清单开始,然后谈谈你的“美元”。
列表
你的bills基本上是特殊列表,构造函数多,没有终止。比如一个普通的列表是这样的:
data List a = SomeElement a List | End
这意味着我们可以构造一个链表,例如:
myList = SomeElement 1 (SomeElement 2 ( End ) )
但是如果我们没有 End
我们就没有办法停止列表。它必须永远SomeElement
。
otherList = SomeElement 1 (SomeElement 2 ( ... oh no, I have to keep going! ...))
返回“美元”
所以你有这张特殊的美元清单。您可以使用 One
和 Five
,而不是用 SomeElement 1
表示一美元和 SomeElement 5
表示五美元钞票。这允许您构建一个“堆栈”的账单:
myMoney = One (Two (Five ( One ...
但是你不能停止,除非你使列表循环,例如让 ...
成为 myMoney
,从而得到无限的 One Two Five One One Two Five One One ...
.
列表
质疑设计
您可能只想要一些简单的东西:
data Dollar = One | Two | Five
然后您可以使用 [One, Two, Five, One]
等普通列表制作美元列表(类型 [Dollar]
)。通过声明 One
账单还包含另一美元(这就是 Dollar = One Dollar
的意思),您创建的不是一张账单而是一张账单列表,这似乎没有用。
我目前正在学习 Haskell,我想为货币 Dollar
(只是钞票,不是硬币)定义我自己的递归数据类型。
我的尝试是这样的:
data Dollar = One Dollar
| Two Dollar
| Five Dollar
| Ten Dollar
| Twenty Dollar
| Fifty Dollar
| Hundred Dollar
我把这个给我的一个朋友看了,他说看起来不错,但他还告诉我在定义的末尾加上一个 | End
。他试图解释为什么有必要,但我无法理解他的思路。也许这里有人有我可以遵循的解释。非常感谢。
您的朋友可能表示在某些时候您需要一个基本案例。给定定义
data Dollar = One Dollar
| Two Dollar
| Five Dollar
| Ten Dollar
| Twenty Dollar
| Fifty Dollar
| Hundred Dollar
| End
您可以将任意数量的钱表示为 Dollar
值的链表,每个值代表一张账单和“剩余”的钱。 End
将终止列表。例如,
fortyTwoDollars :: Dollar
fortyTwoDollars = Twenty (Ten (Five (Five (Two End))))
但是,我看不出有什么理由将列表混入其中;单个 Dollar
值可以单独表示一张账单,您可以使用 [Dollar]
值表示一个集合。
data Dollar = One
| Two
| Five
| Ten
| Twenty
| Fifty
| Hundred
fortyTwoDollars :: [Dollar]
fortyTwoDollars = [Twenty, Ten, Five, Five, Two]
这个不需要递归
描述账单的问题不需要递归类型。让我们从一个清单开始,然后谈谈你的“美元”。
列表
你的bills基本上是特殊列表,构造函数多,没有终止。比如一个普通的列表是这样的:
data List a = SomeElement a List | End
这意味着我们可以构造一个链表,例如:
myList = SomeElement 1 (SomeElement 2 ( End ) )
但是如果我们没有 End
我们就没有办法停止列表。它必须永远SomeElement
。
otherList = SomeElement 1 (SomeElement 2 ( ... oh no, I have to keep going! ...))
返回“美元”
所以你有这张特殊的美元清单。您可以使用 One
和 Five
,而不是用 SomeElement 1
表示一美元和 SomeElement 5
表示五美元钞票。这允许您构建一个“堆栈”的账单:
myMoney = One (Two (Five ( One ...
但是你不能停止,除非你使列表循环,例如让 ...
成为 myMoney
,从而得到无限的 One Two Five One One Two Five One One ...
.
质疑设计
您可能只想要一些简单的东西:
data Dollar = One | Two | Five
然后您可以使用 [One, Two, Five, One]
等普通列表制作美元列表(类型 [Dollar]
)。通过声明 One
账单还包含另一美元(这就是 Dollar = One Dollar
的意思),您创建的不是一张账单而是一张账单列表,这似乎没有用。