Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Control.Applicative ((<*>))
- type Year = Int
- type Date = Int
- data Month = Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec
- deriving (Bounded, Enum, Eq, Ord, Show)
- data DayOfWeek = Sun | Mon | Tue | Wed | Thu | Fri | Sat
- deriving (Bounded, Enum, Eq, Ord, Show)
- data Day = Day Year Month Date DayOfWeek
- deriving (Show)
- buildFridays13From :: Year -> DayOfWeek -> [Day]
- buildFridays13From year dow =
- filter (\(Day _ _ d dof) -> and [d == 13, dof == Fri]) days
- where days = buildFrom year dow
- buildFrom :: Year -> DayOfWeek -> [Day]
- buildFrom year dow = iterate getNextDay (Day year Jan 1 dow)
- getNextDay :: Day -> Day
- getNextDay (Day year month date dayOfWeek) =
- let (_, dof) = wrapSucc dayOfWeek maxBound minBound
- (dateOverflow, d) = wrapSucc date (getDaysInMonth year month) 1
- (monthOverflow, m) = if dateOverflow
- then wrapSucc month maxBound minBound
- else (False, month)
- y = if monthOverflow then succ year else year
- in Day y m d dof
- wrapSucc :: (Ord a, Enum a) => a -> a -> a -> (Bool, a)
- wrapSucc x bound first =
- let overflow = x == bound in (overflow, if overflow then first else succ x)
- getDaysInMonth :: Year -> Month -> Int
- getDaysInMonth year month
- | month == Feb = if isLeap year then 29 else 28
- | isBigMonth month = 31
- | otherwise = 30
- isBigMonth :: Month -> Bool
- isBigMonth month
- | month < Aug = even . fromEnum $ month
- | otherwise = odd . fromEnum $ month
- isLeap :: Year -> Bool
- isLeap year =
- let (h : t) = [divisible 400, not . divisible 100, divisible 4] <*> [year]
- in h || and t
- where divisible divisor x = x `mod` divisor == 0
Advertisement
Add Comment
Please, Sign In to add comment