これがウィキペディアからの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)
...
問題は、splitter/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),
...