#!/usr/bin/env setl
--
-- Luhn tests of credit card numbers in SETL
--
-- From http://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers
-- """
-- The Luhn test is used by some credit card companies to distinguish
-- valid credit card numbers from what could be a random selection of digits.
--
-- Those companies using credit card numbers that can be validated by the
-- Luhn test have numbers that pass the following test:
--
-- 1. Reverse the order of the digits in the number.
-- 2. Take the first, third, ... and every other odd digit in the
-- reversed digits and sum them to form the partial sum s1
-- 3. Taking the second, fourth ... and every other even digit in the
-- reversed digits:
--
-- 1. Multiply each digit by two and sum the digits if the answer
-- is greater than nine to form partial sums for the even digits
-- 2. Sum the partial sums of the even digits to form s2
--
-- 1. If s1 + s2 ends in zero then the original number is in the form
-- of a valid credit card number as verified by the Luhn test.
--
-- For example, if the trail number is 49927398716:
--
-- Reverse the digits:
-- 61789372994
-- Sum the odd digits:
-- 6 + 7 + 9 + 7 + 9 + 4 = 42 = s1
-- The even digits:
-- 1, 8, 3, 2, 9
-- Two times each even digit:
-- 2, 16, 6, 4, 18
-- Sum the digits of each multiplication:
-- 2, 7, 6, 4, 9
-- Sum the last:
-- 2 + 7 + 6 + 4 + 9 = 28 = s2
--
-- s1 + s2 = 70 which ends in zero which means that 49927398716
-- passes the Luhn test
--
-- The task is to write a function/method/procedure/subroutine that will validate a number with the Luhn test, and use it to validate the following numbers:
-- 49927398716
-- 49927398717
-- 1234567812345678
-- 1234567812345670
-- """
--
-- This SETL program was created by Hakan Kjellerstrand (hakank@bonetmail.com)
-- Also see my SETL page: http://www.hakank.org/setl/
--
nums := split("49927398716 49927398717 1234567812345678 1234567812345670", " ");
for n in nums loop
print(n, isluhn10(n));
end loop;
--
-- isluhn10(num) returns #T is valid, else #F
--
-- Assumption: input num is a string.
--
proc isluhn10(num);
x := [val(i) : i in reverse(num)];
m := {[i,val("0246813579"(i+1))] : i in [0..9]};
return +/[x(i) + m(x(i+1)?0) : i in [1,3..#num]] mod 10 = 0;
end proc;