0

I think I have computed Luhn algorithm correctly in Haskell:

f1 :: Integer -> [Integer]
f1 x = if x < 10 then [x] else (f1 (div x 10))++[mod x 10]

f2 :: [Integer] -> [Integer]
f2 xs = [(!!) xs (x - 1) | x <- [1..(length xs)] , even x]

f3 :: [Integer] -> [Integer]
f3 xs = if mod (length xs) 2 /= 0 then (f2 xs) else (f2 (0:xs))

f4 :: [Integer] -> [Integer]
f4 xs = map (*2) (f3 xs)

f5 :: [Integer] -> [[Integer]]
f5 xs = map f1 xs

f6 :: [[Integer]] -> [Integer]
f6 [] = []
f6 (xs : xss) = xs++(f6 xss)

f7 :: [Integer] -> [Integer]
f7 xs = [(!!) xs (x - 1) | x <- [1..(length xs)] , odd x]

f8 :: [Integer] -> [Integer]
f8 xs = if mod (length xs) 2 /= 0 then (f7 xs) else (f7 (0:xs))

f9 :: [Integer] -> [Integer]
f9 xs = (f8 xs) ++ (f4 xs)

f :: Integer -> Integer
f x = sum (f6 (f5 (f9 xs)))
   where xs = f1 x

luhn :: Integer -> Bool
luhn x = if mod (f x) 10 == 0 then True else False

For example,

luhn 49927398716 ==> True
luhn 49927398717 ==> False

Now I have to make a new function sigLuhn such that, given an integer n, with luhn n == True, then sigLuhn n gives the digit (or digits) such that if we add the digit to the final to n, then the new number verifies the Luhn algorithm too; if luhn n == False the function gives an error. For example,

sigLuhn 49927398716 ==> [8]

because if we call n = 49927398716 then

luhn (10*n + 8) ==> True

being 8 the lowest integer from 0. My thought is the next:

g1 :: Integer -> Integer
g1 x = div 10 x + 1

g2 :: Integer -> Integer -> Integer
g2 x y = x*(floor (10)^(g1 y)) + y

g3 :: Integer -> [Bool]
g3 x = [luhn (g2 x y) | y <- [1..]]

g4 :: [Bool] -> Int
g4 xs = minimum (elemIndices True xs)

g :: Integer -> Int
g x = g4 (g3 x)

sigLuhn :: Integer -> [Int]
sigLuhn x = if (luhn x) then [g x] else error "The conditions of Luhn's algorithm are not valid"

The code doesn't give error but sigLuhn is not correct with this code. In short, if we assume that the function luhn is good, can you help me to write sigLuhn correctly? Thank you very much.

ase
  • 13,231
  • 4
  • 34
  • 46
joseabp91
  • 305
  • 2
  • 8
  • 2
    1. It would help if you gave your functions more descriptive names. It's very hard to tell what's going on here. 2. Before assuming the first part works based on a couple tests, I'd do further testing before I move on. I've wasted a lot of time excluding checking a piece of code for a bug because I thought I had thoroughly tested it... and hadn't. – Carcigenicate Feb 02 '17 at 22:38
  • Sorry by the name of the functions. I had to translate to english many words and I forgot to translate the name of the functions too. – joseabp91 Feb 02 '17 at 22:43
  • Well, to be honest, I don't know what the Luhn algorithm is or how to implement it, but for anyone who can help you with it, you should try to make it as easy as possible for them. – Carcigenicate Feb 02 '17 at 22:45
  • I want to say here again that I'm almost sure that `luhn` is correct. Only I have to write better `sigLuhn`. – joseabp91 Feb 02 '17 at 22:48
  • OK, well, unfortunately, I can't help with that part. I'd say start debugging by checking each helper function to ensure they're returning what you'd expect. – Carcigenicate Feb 02 '17 at 22:49

1 Answers1

1

I assigned it in a class last fall. Here's one of the best solutions.

doubleAndSum :: [Int] -> Int
doubleAndSum = fst . foldr (\i (acc, even) -> (acc + nextStep even i, not even)) (0,False)
  where 
    nextStep even i
        | even      = (uncurry (+) . (`divMod` 10) . (*2)) i
        | otherwise = i 

myLuhn :: Int -> Bool
myLuhn = (0 ==) . (`mod` 10) . doubleAndSum . (map (read . (: ""))) . show

testCC :: [Bool]
testCC = map myLuhn [49927398716, 49927398717, 1234567812345678, 1234567812345670]
-- => [True,False,False,True]
RussAbbott
  • 2,660
  • 4
  • 24
  • 37
  • You should explain your changes. This is fairly vague as is. – Carcigenicate Feb 03 '17 at 02:58
  • You have to know what the Luhn algorithm does. Given that, doubleAndSum sums the digits, doubling even digit from the right. If a doubled digit exceeds 9, those digits are summed also. myLuhn converts the input Int to a list of single-digit Ints, calls doubleAndSum on the list, and returns True or False depending on whether the sum mod10 is 0. – RussAbbott Feb 03 '17 at 07:08