Haskell Luhn Algorithm
One thing that immediately pops out (and happens a lot with beginner Haskell programmers, IME):

s2 = sum $ map sumDigits $ map (*2) es 


This means (reads as for me) "map (*2) on es, then map sumDigits on it, then sum the numbers."

What you typically want to do is to stay on the "function side" on things as long as possible:

s2 = sum . map sumDigits . map (*2) $ es 


Meaning you compose as much as you can, and put only one application at the end. That makes it easier to eta-reduce and in general is considered more idiomatic.



You could also compose the mapped operation, bringing it down to classic "map-reduce" scenario (where "map" part is sumDigits . (*2), and "reduce" part is the sum).

s2 = sum . map (sumDigits . (*2)) $ es 




I'd also flip the order of Valid and Invalid:

data Validity = Invalid | Valid deriving Eq


This way, when you derive Ord, Valid &gt; Invalid, which is sometimes helpful and in general you'll see that it holds "intuitively", for Maybe (Just _ &gt; Nothing), Either (Right _ &gt; Left _) and similar values.