这是我从维基百科翻译的 Python
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.
除了更冗长之外,上面页面中的测试用例似乎是正确的。但:
?- is_luhn_valid(123).
false.
而你的代码:
?- luhn(123).
true ;
true ;
...
而且当然
?- luhn(124).
....
不会终止。所以,你陷入了一个失败循环,每次都要求 Prolog 试图证明一个无法解决的目标......
痕迹片段:
?- 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)
...
问题似乎是 spliter/2 不断在序列前面添加 0,而它应该失败。
关于效率:我的片段可以重写为
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.
利用库(聚合)
编辑
我认为 spliter/2 应该检查 N > 0,否则它将永远递归......尝试
spliter(N,L):- N>0,
N1 is floor(N/10),
...