1
votes

I'm expecting luhn 5594589764218858 = True but it is always False

-- Get the last digit from a number
lastDigit :: Integer -> Integer
lastDigit 0 = 0
lastDigit n = mod n 10

-- Drop the last digit from a number
dropLastDigit :: Integer -> Integer
dropLastDigit n = div n 10

toRevDigits :: Integer -> [Integer]
toRevDigits n
  | n <= 0    = []
  | otherwise = lastDigit n : toRevDigits (dropLastDigit n)

-- Double every second number in a list starting on the left.
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther []       = []
doubleEveryOther (x : []) = [x]
doubleEveryOther (x : y : z) = x : (y * 2) : doubleEveryOther z

-- Calculate the sum of all the digits in every Integer.
sumDigits :: [Integer] -> Integer
sumDigits []          = 0
sumDigits (x : [])    = x
sumDigits (x : y)     = (lastDigit x) + (dropLastDigit x) + sumDigits y

-- Validate a credit card number using the above functions.
luhn :: Integer -> Bool
luhn n
  | sumDigits (doubleEveryOther (toRevDigits n)) `div` 10 == 0 = True
  | otherwise                                                  = False

I know it can be done easier but I'm following a Haskell introductory. I think my only problem is in the luhn function. The course mentions problems may occur because toRevDigits reverses the number but I think it should work anyways.

1
I would suggest writing some tests for each of those components (a good opportunity to learn quickcheck, if you have a little time). - jberryman
@BradyDean Your sumDigits function is wrong. Consider this example. lastDigit 123 returns 3. dropLastDigit 123 returns 12. However 3 + 12 is not equal to the sum of the digits (1 + 2 + 3). - jub0bs
The digits are being split up. sumDigits [10, 5, 18, 4] = 1 + 0 + 5 + 1 + 8 + 4 = 19 is what I'm going for - Brady Dean
@BradyDean You're only getting a correct result in your example because all integers happen to have no more than two digits. Try sumDigits [1,100]. - jub0bs
@Jubobs Only handling values with at most two digits is sufficient in this case since doubleEveryOther will never yield numbers > 9*2. - Frerich Raabe

1 Answers

1
votes

The snippet x `div` 10 == 0 is not a correct check that x is divisible by ten; you should use `mod` instead. Also, this equation is incorrect:

sumDigits (x : [])    = x

(Try, e.g. sumDigits [10].) It can be fixed, but deleting it is simpler and still correct.