Leap year check in Haskell, using pattern matching or bind operator
The first one is a lot more readable, whereas the second one uses a "hack". I would go with the first one, except that I would use rem, which is a little bit faster. And one could introduce some DRY:

isDivisibleBy :: Integral n =&gt; n -&gt; n -&gt; Bool
isDivisibleBy x n = x `rem` n == 0

isLeapYear :: Integer -&gt; Bool
isLeapYear year
  | divBy 400 = True
  | divBy 100 = False
  | divBy   4 = True
  | otherwise = False
 where
   divBy n = year `isDivisibleBy` n


That being said, for a programming challenge, your version is perfectly fine:

isLeapYear :: Integer -&gt; Bool
isLeapYear year
  | year `rem` 400 == 0 = True
  | year `rem` 100 == 0 = False
  | year `rem`   4 == 0 = True
  | otherwise           = False




The latter can be rewritten without &gt;&gt;= as list comprehension:

isLeapYear :: Integer -&gt; Bool
isLeapYear year = head [isLeap | (interval, isLeap) &lt;- classifications
                               , year `isDivisibleBy` interval]
  where
    classifications = [(400, True), (100, False), (4, True), (1, False)]


You could get rid of the "hack" with safeHead and maybe False, but that's left as an exercise.

If you really want to use check, remove the y. It just introduces an additional error source:

isLeapYear :: Integer -&gt; Bool
isLeapYear year = head $
                  [(400, True), (100, False), (4, True), (1, False)]
                  &gt;&gt;= check
  where check (interval, isLeap) = [isLeap | year `rem` interval == 0]


Note that this shows perfectly that &gt;&gt;= is just flip concatMap for lists. So let's take advantage:

isLeapYear :: Integer -&gt; Bool
isLeapYear year = head $ concatMap check classifications ++ [False]
  where 
    check (interval, isLeap) = [isLeap | year `rem` interval == 0]
    classifications = [(400, True), (100, False), (4, True)]


Which is easier to grasp than the version with &gt;&gt;=.