data Weekday = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday deriving (Show, Eq, Ord, Enum) data Month = January | February | March | April | May | June | July | August | September | October | November | December deriving (Show, Eq, Ord, Enum) type Day = Int type Year = Int data Date = Date Year Month Day Weekday deriving (Show, Eq, Ord) nextWeekday :: Weekday -> Weekday nextWeekday Sunday = Monday nextWeekday d = succ d nextMonth :: Month -> Month nextMonth December = January nextMonth m = succ m getDays :: Month -> Year -> Int getDays m y | elem m [September, April, June, November] = 30 | m == February = if rem y 4 == 0 && if rem y 100 == 0 && rem y 400 /= 0 then False else True then 29 else 28 | otherwise = 31 nextDate :: Date -> Date nextDate (Date y m d wd) | d < getDays m y = Date y m (d+1) (nextWeekday wd) | m == December = Date (y+1) January 1 (nextWeekday wd) | otherwise = Date y (nextMonth m) 1 (nextWeekday wd) daysTwentieth :: [Date] daysTwentieth = takeWhile (\(Date y _ _ _) -> y /=2001) (dates start) where dates d = d:dates (nextDate d) start = Date 1901 January 1 Tuesday e019 = length . filter (\(Date y m d wd) -> d == 1 && wd == Sunday) $ daysTwentieth