Difference between revisions of "Haskell Quiz/Credit Cards/Solution Dolio"

From HaskellWiki
Jump to navigation Jump to search
m
 
Line 46: Line 46:
 
. (\l -> [if luhn l then "Valid" else "Invalid", cardType l, "card"])
 
. (\l -> [if luhn l then "Valid" else "Invalid", cardType l, "card"])
 
. map (digitToInt) . concat =<< getArgs
 
. map (digitToInt) . concat =<< getArgs
  +
</hasekll></haskell>
+
</haskell>

Latest revision as of 07:32, 28 April 2007


This solution does nothing particularly special. The constraints on each type of card are expressed as guards in some MonadPlus, which allows the results of those functions to be summed to get a result. The Luhn algorithm is fairly straight forward list processing.

The program expects command line arguments consisting only of the credit card number. The arguments are concatenated into a single string, so one can use as many or as few spaces to break it up as they wish.

import Control.Monad
import Data.Char
import Data.List
import Data.Maybe
import System.Environment

luhn :: [Int] -> Bool
luhn = (==0) . (`mod` 10) . sum . foldr split [] . zipWith ($) (cycle [id, (*2)]) . reverse

split n l
    | n > 9     = split d (m:l)
    | otherwise = n:l
 where (d, m) = divMod n 10

amex l@(x:y:_) = do guard $ length l == 15
                    guard $ x == 3
                    guard $ y `elem` [4, 7]
                    return "AMEX"

discover l = do guard $ length l == 16
                guard $ [6,0,1,1] `isPrefixOf` l
                return "Discover"

visa l@(x:_) = do guard $ length l `elem` [13, 16]
                  guard $ x == 4
                  return "Visa"

mastercard l@(x:y:_) = do guard $ length l == 16
                          guard $ x == 5
                          guard $ y `elem` [1..5]
                          return "Mastercard"

unknown l = return "Unknown"

cardType l = fromJust . msum . map ($ l) $ [amex, discover, visa, mastercard, unknown]

main = putStrLn . unwords
        . (\l -> [if luhn l then "Valid" else "Invalid", cardType l, "card"])
        . map (digitToInt) . concat =<< getArgs