haskell enum - what to do in case value constructors require value instead of nullary? Requirement scenario is given

StackOverflow https://stackoverflow.com//questions/11661878

Question

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;
}

Was it helpful?

Solution

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

OTHER TIPS

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top