Skip to content

Instantly share code, notes, and snippets.

@bmabey
Created September 16, 2014 04:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bmabey/b4a1494381fd06353685 to your computer and use it in GitHub Desktop.
Save bmabey/b4a1494381fd06353685 to your computer and use it in GitHub Desktop.
Credit Card Validation
toDigits :: Integer -> [Integer]
toDigits 0 = []
toDigits x = toDigits (div x 10) ++ [(mod x 10)]
toDigitsRev :: Integer -> [Integer]
toDigitsRev 0 = []
toDigitsRev x = (mod x 10) : toDigitsRev (div x 10)
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther = (reverse . (zipWith ($) (cycle [id, (*2)])) . reverse)
sumDigits :: [Integer] -> Integer
sumDigits xs = sum (concatMap toDigits xs)
validate :: Integer -> Bool
validate x = (mod ((sumDigits . doubleEveryOther . toDigits) x) 10) == 0
@bmabey
Copy link
Author

bmabey commented Sep 16, 2014

My doubleEveryOther is pretty naive with the double reverse but I figured that since we know n is always small it doesn't really matter.

@paul-english
Copy link

I also had the doubled up reverse, I wonder what the trick might be to avoid that.

@pinealservo
Copy link

This is one way to avoid double-reverse; due to the right-associative nature of foldr, the initial argument will pair with the rightmost element of the list. We can pair each argument with an extra value (isomorphic to Boolean, if you don't want to create a new type for it) to keep track of whether we should double or not. At the end of the recursion, simply discard the parity value.

data Parity = Even | Odd
            deriving (Eq, Show)

doubleEveryOther = snd . foldr place init
  where
    init = (Even, [])
    place x (Even, xs) = (Odd , x:xs)
    place x (Odd,  xs) = (Even, (x*2):xs)

You can write it a bit more succinctly, but I prefer clarity over succinctness when they conflict.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment