Вот мой перевод Python от Wikipedia
is_luhn_valid(Card_number):-
luhn_checksum(Card_number, 0).
luhn_checksum(Card_number, Checksum) :-
digits_of(Card_number, Digits),
findall(D, (nth0(I, Digits, D), I mod 2 =:= 0), Odd_digits),
findall(D, (nth0(I, Digits, D), I mod 2 =:= 1), Even_digits),
sum_list(Odd_digits, Checksum_t),
findall(S, (
member(T, Even_digits),
T1 is T * 2,
digits_of(T1, D1),
sum_list(D1, S)
), St),
sum_list(St, St1),
Checksum is (Checksum_t + St1) mod 10.
digits_of(Number, Digits) :-
number_codes(Number, Cs),
maplist(code_digit, Cs, Digits).
code_digit(C, D) :- D is C - 0'0.
друг от друга быть более многословным, это кажется правильным WRT тестовый пример из приведенной выше страницы. Но:
?- is_luhn_valid(123).
false.
в то время как ваш код:
?- luhn(123).
true ;
true ;
...
и, конечно
?- luhn(124).
....
не прекращается. Таким образом, вы придерживаться в цикле отказа, где Пролог просит каждый раз, чтобы попытаться доказать неразрешимую задачу ...
фрагмент следа:
?- leash(-all),trace.
true.
[trace] ?- luhn(124).
Call: (7) so:luhn(124)
Call: (8) so:spliter(124, _G9437)
...
Exit: (8) 2 is 12 mod 10
Call: (8) 2 is 0
Fail: (8) 2 is 0
Redo: (11) so:spliter(0, _G9461)
Call: (12) _G9465 is floor(0/10)
...
Проблема, кажется, что сплитер/2 добавляет 0s перед последовательностью, в то время как вместо этого он должен выйти из строя.
Об эффективности: мой фрагмент кода можно переписать в виде
luhn_checksum(Card_number, Checksum) :-
digits_of(Card_number, Digits),
aggregate_all(sum(V), (
nth0(I, Digits, D),
( I mod 2 =:= 0
-> V = D % Odd_digits
; Dt is D * 2, % Even_digits
digits_of(Dt, Ds),
sum_list(Ds, V)
)),
Checksum_t),
Checksum is Checksum_t mod 10.
использования библиотеки (aggregate)
редактировать
Я думаю сплитер/2 должны проверить, если N> 0, в противном случае он будет возвращаться навсегда ... try
spliter(N,L):- N>0,
N1 is floor(N/10),
...
'0 =: = Res mod 10' является более кратким. – false
'N1 is N div 10' более точно (для очень больших чисел). – false