GIGO: words unreadable aloud
Mishrogo Weedapeval
 

 

  Thursday 31 October 2002
Luhn-acy in Haskell, Scala, and yet another Python version

Joey "Happiest Accordian Guyeek" de Villa has a couple of weblog entries about the Luhn Algorithm, used for a checksum on some credit card numbers. Joey has been getting some examples in several languages; I thought I'd contribute a Haskell version and a Scala version, and the recursive Python version that I did first.

Here's my Haskell one, tested (a little bit) on both hugs and GHC:

-- These five lines are the actual code:
luhn_sub 0 _ = 0
luhn_sub n m =
   (luhn_sub (n `div` 10) (3 - m)) + do_dig (m * (n `mod` 10))
   where do_dig n = if n <= 9 then n else n - 9
luhn str = (luhn_sub (read str) 1) `mod` 10 == 0

-- These five lines run a small pair of tests:
t9 base = (map (base ++) (map show [0..9]))
prTest = 
   let test_strs = concat $ map t9 ["234234", "5128960128"] in
   let results = map (\s -> (s ++ " -> " ++ show (luhn s))) 
test_strs in
   mapM_ putStrLn results


Thanks for blowing my whole damn day, Joey! :-D

Here's the Scala version: (see http://radio.weblogs.com/0100945/2002/07/04.html )

module Luhn with {
    def do_dig (dig: Long): Long = {
        if (dig <= 9) dig
        else dig-9;
    }
    def luhn_sub (nr:Long, mul:Long): Long = {
        if (nr == 0) { 0; }
        else {
            val d = mul * (nr % 10);
            luhn_sub(nr/10, 3-mul) + do_dig(d)
        }
    }
    // I guess the java.lang... call is the normal Scala way
    //  to convert a Scala string to a Long -- I can't figure out
    //  much from the Scala libraries.  Need Long instead of Int
    //  because them Credit Card numbers are big.
    def luhn (nrStr:String):Boolean = {
        val nr = java.lang.Long.parseLong(nrStr);
        val lsum = luhn_sub(nr, 1);
        lsum % 10 == 0
    }
    // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    //  Above is the Luhn algorithm code.  From here down, it's
    //   all just testing code.
    // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    def lrange (lo: Long, pastHi: Long): List[Long] = {
        if (lo >= pastHi) []
        else lo :: lrange(lo + 1, pastHi);
    }
    def test_tens () = {
        def tens (s:String) = {
            for( val dig <- lrange(0,10) ) yield {
                val sd = s + dig;
                System.out.println( "Luhn(" + sd + ") = " + luhn(sd) )
            }
        }
        tens( "234234" );
        tens( "5128960128" );
        nil
    }
}
Luhn.test_tens();


And, finally, here's the recursive Python version that preceded the other FP solutions:

def luhn( ccStr ):
    def do_dig ( d ):
        if d > 9: d -= 9
        return d
    def sub ( ccNr, mult ):
        if ccNr:
            return sub( ccNr/10, 3 - mult ) + 
                   do_dig( mult * (ccNr%10) )
        return 0
    return ( sub(long(ccStr),1) % 10) == 0

def test ( ):
    for tn in [ 234234, 5128960128 ]:
        for i in range(9):
            tnt = tn * 10 + int(i)
            print tnt, luhn(`tnt`)

if __name__ == '__main__':
    test()

12:43:32 AM   comment/     


Click here to visit the Radio UserLand website. Click to see the XML version of this web page. © Copyright 2007 Doug Landauer .
Last update: 07/2/6; 12:20:39 .
Click here to send an email to the editor of this weblog.

October 2002
Sun Mon Tue Wed Thu Fri Sat
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
Sep   Nov

Previous/Next