You can eta-reduce blowupCreditCardNumber
:
blowupCreditCardNumber = zip [1..]
Using composition, you can also make isCreditCardNumber pointfree:
isCreditCardNumber = (==0) . creditCardReminder . creditCardDouble . blowupCreditCardNumber . reverse
You don't need to optimize numberDoubleToList
by special-casing the one-digit case.
numberDoubleToList = map digitToInt . show
The explicit recursion in creditCardDouble
can be averted by using library functions that specialize in particular recursive patterns:
creditCardDouble = concatMap foo where
foo (index, digit) | even index = numberDoubleToList $ (*2) $ digitToInt digit
| otherwise = [digitToInt digit]
foo
's name makes foo
look like a crutch, and that is good, because it is one.
I would inline definitions that are only used once and do not deserve to be in a library:
isCreditCardNumber = (==0) . (`mod` 10) . sum . concatMap foo . zip [1..] . reverse where
foo (index, digit) | even index = map digitToInt $ show $ (*2) $ digitToInt digit
| otherwise = [digitToInt digit]
digitToInt digit
is used in both cases of foo, and so can be factored out:
isCreditCardNumber = (==0) . (`mod` 10) . sum . concatMap foo . zip [1..] . reverse where
foo (index, digit) = bar index $ digitToInt digit
bar index | even index = map digitToInt . show . (*2)
| otherwise = pure
In fact, we don't need to generate the index and pass it to foo
if all we do with it is put it into bar
later:
isCreditCardNumber = (==0) . (`mod` 10) . sum . concatMap foo . zip (cycle [pure, map digitToInt . show . (*2)]) . reverse where
foo (doubler, digit) = doubler $ digitToInt digit
foo
is almost trivial, lets get rid of it entirely:
isCreditCardNumber = (==0) . (`mod` 10) . sum . concat . zipWith ($) (cycle [pure, map digitToInt . show . (*2)]) . map digitToInt . reverse
map digitToInt . show
is pure
on single digits, so we can factor it out of that list and then even factor out the (*)
:
isCreditCardNumber = (==0) . (`mod` 10) . sum . concatMap (map digitToInt . show) . zipWith (*) (cycle [1, 2]) . map digitToInt . reverse
Note that if you know the parity of the length of the credit card number, you can get rid of the reverse
.