在 ADT 中定义 Haskell 中的非 Int 常量

Jir*_*Jir 1 haskell constants algebraic-data-types

我正在学习 Haskell,作为该过程的一部分,我正在尝试构建一个玩具程序,将披萨尺寸建模为代数数据类型。

到目前为止,我已经想出了这个:

    data Size = Small | Medium | Large | ExtraLarge
        deriving Show
Run Code Online (Sandbox Code Playgroud)

从某种意义上说,这是可以的,因为它模拟了有效大小是有限且已定义的事实,但它没有模拟这些大小的数值有多大的概念。

正如这篇 SO post 中所建议的,一种解决方案可能是从 和 派生并Enum编写。话又说回来,这些函数的签名要求从我不喜欢的类型进行转换——首先是因为大小不自然,然后是因为我可能决定使用自定义数据类型(例如,)。fromEnumtoEnumIntIntInch

我可以创建一堆常量,例如:

    Small = 9.5             
    Medium = 11.5
    ...
Run Code Online (Sandbox Code Playgroud)

但我也想将它们分组为“正确的”数据类型。

有什么建议如何继续前进吗?

chi*_*chi 6

您可以定义一个函数,将每个大小值与一个数值相关联。例如

sizeToInch :: Size -> Double
sizeToInch Small  = 9.5
sizeToInch Medium = 11.5
...
Run Code Online (Sandbox Code Playgroud)

如果需要,您还可以使用自定义类型来更好地表示单位:

newtype Inch = Inch { fromInch :: Double }

sizeToInch :: Size -> Inch
sizeToInch Small  = Inch 9.5
sizeToInch Medium = Inch 11.5
...
Run Code Online (Sandbox Code Playgroud)

请注意,上述Inch类型不允许您直接Inch使用 求和+,或使用标准运算符执行任何其他算术运算。您可能需要添加deriving Num以启用该类型的标准运算符。不过,这也将允许乘法,但这并不理想(一平方英寸不是一英寸)​​。有一些库(例如dimensional)可以严格处理单元,但对于如此简单的任务,它们可能有些过头了。选择您最舒服的设计。