How do I make my Haskell function as short as possible?

Viewed 921

The season function uses algebraic functions but I feel like the code is repetitive.

How do I make it as short as possible?

data Month = Jan | Feb | Mar | Apr | May | June | July | Aug | Sept| Oct | Nov | Dec
     deriving (Eq,Ord,Show,Read)

data Seasons = Spring | Summer | Autumn | Winter
     deriving (Eq,Ord,Show,Read)

season :: Month -> Seasons
season Jan = Winter
season Feb = Winter
season Mar = Spring
season Apr = Spring
season May = Spring
season June = Summer
season July = Summer
season Aug = Summer
season Sept = Autumn
season Oct = Autumn
season Nov = Autumn
season Dec = Winter
3 Answers

You can make use of guards, since you made Month an instance of Ord:

season :: Month -> Seasons
season m | m <= Feb = Winter
         | m <= May = Spring
         | m <= Aug = Summer
         | m <= Nov = Autumn
         | otherwise = Winter

Add Enum to both your data type definitions' deriving clauses, then

season :: Month -> Seasons
season m  =  toEnum ((fromEnum m - 2) `div` 3 `mod` 4)

Three months in a season, four seasons in a year, spring starting in March.

This is very similar to Will Ness' answer (doing arithmetic on month indices through Enum instances), only with a few tweaks for the sake of readability:

data Month = Jan | Feb | Mar | Apr | May | June | July | Aug | Sept | Oct | Nov | Dec
     deriving (Eq, Ord, Show, Read, Enum)

data Season = Spring | Summer | Autumn | Winter
     deriving (Eq, Ord, Show, Read, Enum)

season :: Month -> Season
season = toEnum . (`div` 3) . monthIndexStartingFrom Mar
    where
    monthIndexStartingFrom :: Month -> Month -> Int
    monthIndexStartingFrom base month = (fromEnum month - fromEnum base) `mod` 12

In any case, there is something to be said in support of your original solution listing all cases explicitly, for its sheer straightforwardness. The repetitiveness in writing it can be reduced somewhat by using a case-statement instead of multiple equations.

Related