0
votes

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.

1
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
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
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
I want to say here again that I'm almost sure that luhn is correct. Only I have to write better sigLuhn. - joseabp91
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

1 Answers

1
votes

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]