haskell enum - 如果值构造函数需要值而不是空值,该怎么办?给出了需求场景
Posted
技术标签:
【中文标题】haskell enum - 如果值构造函数需要值而不是空值,该怎么办?给出了需求场景【英文标题】:haskell enum - what to do in case value constructors require value instead of nullary? Requirement scenario is given 【发布时间】:2012-07-24 14:26:26 【问题描述】:LYAH 在Derived Instances 说
[...] 所有的值构造函数都是空的(不带参数,即字段),我们可以将其作为 Enum 类型类的一部分。
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday deriving (Eq, Ord, Show, Read, Bounded, Enum)
现在,如果我需要几个月,那就是
data month = January | February | March | April | May | June | July | August |September | October | November |December deriving (Eq, Ord, Show, Read, Bounded, Enum)
我的问题是:
-
在哪里存储每个月的 Max Days 值?
如果是闰年,那么二月的 maxDays 是 29 天,否则是 28 天,如何提及和控制?
在 Java 中可以编写如下代码:
public enum Month
January (31),
February (29),
March (31),
April (30),
May (31),
June (30),
July (31),
August (31),
September (30),
October (31),
November (30),
December (31),
;
private int maxDays; // instance variables
private (int maxDays) // constructors always private
this.maxDays = maxDays;
Public int getMaxDays ()
return maxDays;
【问题讨论】:
您应该使用time 包,它是由真正了解情况的人编写的。 您要求的不是Enum
的有效实例。 Enum
类用于可以在不丢失信息的情况下与Int
的子集相互转换的类型。您已经为几个月分配了相同的数字,这使得这种转换变得不可能。
@Optimight:在您的 Day 示例中,deriving(Enum)
子句生成Enum
的有效实例。具体来说,生成的函数每天都会给出不同的Int
值。 Monday = 0
, Tuesday = 1
, ... Sunday = 6
.
@HeatSink:在这种情况下,对于数据 Month 的第二个示例,也给出 January = 0, February = 1, ... December = 11。唯一的事情,它进一步将 maxDays 的值附加到每个月。
@Optimight,我明白了。您希望 maxDays 与构造函数 ID 分开。
【参考方案1】:
这应该可行。
data Month = January | February | March | April | May
| June | July | August |September | October
| November | December
deriving (Eq, Ord, Show, Read, Bounded, Enum)
type Year = Int
isLeapYear :: Year -> Bool
isLeapYear year = year `mod` 4 == 0 && (year `mod` 100 /= 0 || year `mod` 400 == 0)
getMaxDays :: Year -> Month -> Int
getMaxDays _ January = 31
getMaxDays year February
| isLeapYear year = 29
| otherwise = 28
getMaxDays _ March = 31
getMaxDays _ April = 30
getMaxDays _ May = 31
getMaxDays _ June = 30
getMaxDays _ July = 31
getMaxDays _ August = 31
getMaxDays _ September = 30
getMaxDays _ October = 31
getMaxDays _ November = 30
getMaxDays _ December = 31
【讨论】:
【参考方案2】:为什么需要Month
成为枚举?在我看来,您正试图在代码中强制采用 OO 样式,这不是一个好主意。 Java 面向对象的代码编写风格不能完全转换为 Haskell 等函数式语言。
在 OO 中,您可以将数据结构和对该数据的所有相关操作捆绑在一个类中,而在 FP 中,您可以将数据结构与相关操作分开定义。这意味着 FP 方法可以更轻松地定义对数据的新操作,而 OO 方法可以更轻松地将新信息添加到数据结构中。就我个人而言,我发现自己定义新操作比添加新字段和 FP 风格套装要多得多。
与 Haskell 中的 Java 示例最接近的类似物是定义一个 Typeclass -
data Month = January | February | March | April
| May | June | July | August |September
| October | November |December
deriving (Eq, Ord, Show, Read, Bounded, Enum)
data Year = Int
class HasDays X where
maxdays :: X -> Int
days :: X -> Year -> Int
-- Any other "methods" here
instance HasDays Month where
maxdays January = 31
maxdays February = 29
maxdays .. = .. -- Similar code for other months
days February y = .. -- Leap year calculation
days m _ = maxdays m
【讨论】:
我习惯了 OO 范式,但是在选择 FP 时,它必须是纯正的 FP 方法。以上是关于haskell enum - 如果值构造函数需要值而不是空值,该怎么办?给出了需求场景的主要内容,如果未能解决你的问题,请参考以下文章