Last active
April 30, 2016 14:12
-
-
Save alskipp/55b28891412ae0cf0d51 to your computer and use it in GitHub Desktop.
Credit card validation in Swift for Swift London Meetup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Swift 2.0 | |
/* Function composition operator */ | |
infix operator •> { associativity left precedence 150 } | |
func •> <A,B,C> (f:A -> B, g:B -> C ) -> A -> C { | |
return { g(f($0)) } | |
} | |
extension Array where T: IntegerType { | |
func sum() -> T { | |
return self.reduce(0, combine: +) | |
} | |
} | |
func toDigitsRev(num:Int) -> [Int] { | |
if case 0...9 = num { return [num] } | |
return [num % 10] + toDigitsRev(num/10) | |
} | |
func doubleSecond(nums:[Int]) -> [Int] { | |
return nums.enumerate().map { i, x in | |
i % 2 == 0 ? x : x * 2 | |
} | |
} | |
func sumDigits(nums:[Int]) -> Int { | |
return nums.flatMap(toDigitsRev).sum() | |
} | |
let isValid = | |
toDigitsRev | |
•> doubleSecond | |
•> sumDigits | |
•> { $0 % 10 == 0 } | |
/* Example */ | |
isValid(4716347184862961) // > true | |
isValid(5716347184862961) // > false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Swift 2.0 | |
// Pushing the function composition idea even further 😈 | |
/* Curried flatMap & reduce functions (taking function as first arg) */ | |
func flatMap<A,B>(f:A -> [B])(_ xs:[A]) -> [B] { | |
return xs.flatMap(f) | |
} | |
func reduce<A,B>(f:(B, A) -> B)(_ i:B)(_ xs:[A]) -> B { | |
return xs.reduce(i, combine: f) | |
} | |
infix operator •> { associativity left precedence 150 } | |
func •> <A,B,C> (f:A -> B, g:B -> C ) -> A -> C { | |
return { g(f($0)) } | |
} | |
/* Implementation */ | |
func toDigitsRev(num:Int) -> [Int] { | |
if case 0...9 = num { return [num] } | |
return [num % 10] + toDigitsRev(num/10) | |
} | |
func doubleSecond(nums:[Int]) -> [Int] { | |
return nums.enumerate().map { i, x in | |
i % 2 == 0 ? x : x * 2 | |
} | |
} | |
let sum = reduce(+)(0) | |
let sumDigits = flatMap(toDigitsRev) •> sum | |
let isValid = | |
toDigitsRev | |
•> doubleSecond | |
•> sumDigits | |
•> { $0 % 10 == 0 } | |
/* Example */ | |
isValid(4716347184862961) // > true | |
isValid(5716347184862961) // > false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Swift 1.2 | |
/* A few handy functions to simplify(!) code */ | |
infix operator |> { associativity left precedence 150 } // Pipe-Forward (F#) | |
func |> <T,U> (lhs:T, rhs:T -> U ) -> U { | |
return rhs(lhs) | |
} | |
infix operator >>= { associativity left } // bind (Haskell) | |
func >>= <T,U>(elements:[T], f:T -> [U]) -> [U] { | |
return reduce(elements, []) { $0 + f($1) } | |
} | |
func sum(xs:[Int]) -> Int { | |
return reduce(xs, 0, +) | |
} | |
/* Implementation of credit card validation */ | |
func toDigitsRev(num:Int) -> [Int] { | |
switch num { | |
case 0...9 : return [num] | |
default : return [num % 10] + toDigitsRev(num/10) | |
} | |
} | |
func doubleSecond(nums:[Int]) -> [Int] { | |
return map(enumerate(nums)) { i, x in | |
i % 2 == 0 ? x : x * 2 | |
} | |
} | |
func sumDigits(nums:[Int]) -> Int { | |
return sum(nums >>= toDigitsRev) | |
} | |
func isValid(num:Int) -> Bool { | |
return toDigitsRev(num) |> doubleSecond |> sumDigits % 10 == 0 | |
} | |
/* Usage example */ | |
isValid(4716347184862961) // > true | |
isValid(5716347184862961) // > false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- Haskell implementation of creditcard validation -} | |
import Control.Monad | |
toDigitsRev :: Integer -> [Integer] | |
toDigitsRev n | |
| n < 10 = [n] | |
| otherwise = n `mod` 10 : toDigitsRev (n `div` 10) | |
doubleSecond :: [Integer] -> [Integer] | |
doubleSecond [] = [] | |
doubleSecond (x:y:ys) = x : y * 2 : doubleSecond ys | |
doubleSecond (x:xs) = x : xs | |
sumDigits :: [Integer] -> Integer | |
sumDigits xs = sum $ xs >>= toDigitsRev | |
isValid :: Integer -> Bool | |
isValid = (0 ==) . (`mod` 10) . sumDigits . doubleSecond . toDigitsRev | |
{- Example Usage | |
isValid 4716347184862961 -- True | |
isValid 5716347184862961 -- False | |
-} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A description of the algorithm is here http://en.wikipedia.org/wiki/Luhn_algorithm
The Swift code is heavily influenced by my Haskell implementation for the following online course: http://t.co/G9YfG1og2t
Swift London: http://www.meetup.com/swiftlondon/