问题描述
我目前正在学习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,Two]
,
这不需要递归
描述帐单的问题不需要递归类型。让我们从列表开始,然后谈论您的“美元”。
列表
您的账单基本上是特殊的清单,具有更多的构造函数且没有终止。例如,普通列表如下:
address
这意味着我们可以构建一个链接列表,例如:
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! ...))
和SomeElement 1
来代替使用SomeElement 5
来换一美元和使用One
来换五美元的钞票。这使您可以构造一个“堆栈”票据:
Five
但是您无法停止,除非您进行列表循环,例如将myMoney = One (Two (Five ( One ...
设为...
,从而得到myMoney
的无限列表。
质疑设计
您可能只想简单一些:
One Two Five One One Two Five One One ...
然后,您可以使用诸如data Dollar = One | Two | Five
之类的普通清单制作一个美元清单(类型[Dollar]
)。声称[One,Two,One]
账单还包含另一美元(这就是One
的意思),您创建的不是单个账单,而是它们的列表,这似乎没有用。