haskell enum - what to do in case value constructors require value instead of nullary? Requirement scenario is given
-
11-12-2019 - |
Pergunta
LYAH says at Derived Instances that "all the value constructors are nullary (take no parameters, i.e. fields), we can make it part of the Enum typeclass."
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
deriving (Eq, Ord, Show, Read, Bounded, Enum)
Now, if I take months, it will be
data month = January | February | March | April | May | June | July | August |September | October | November |December
deriving (Eq, Ord, Show, Read, Bounded, Enum)
My Question is: (1) Where to store Max Days value for each month? (2) How to mention and control that for February month if it is leap year then maxDays for February is 29 days otherwise it will be 28 days?
In Java one can code like given below:
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;
}
Solução
This should work.
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
Outras dicas
Why do you need Month
to be an Enum? It seems to me that you are trying to force an OO style in your code, which is not a good idea. The Java object oriented style of writing code does not cleanly translate to functional languages like Haskell.
Where in OO, you would bundle the data structure and all associated operations on that data in a class, in FP, you would define the data structure separately from the associated operations. This means that the FP approach makes it easier to define new operations on data, where as OO approach makes it easier to add new information to your data structure. Personally I find myself defining new operations a lot more than adding new fields and FP style suits that well.
The closest analogue to the Java example in Haskell would be to define a 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