整数と数字のリストであるという述語を記述し、Digits に整数の数字が適切な順序で含まれている場合に成功します。つまり、次のようになります。
?-digit_lists( Num, [1,2,3,4] ).
[Num == 1234].
これが私がこれまでに持っているものです:
my_digits( 0, [] ).
my_digits(N,[A|As]) :- N1 is floor(N/10), A is N mod 10, my_digits(N1, As).
すでに提案したように、有限領域制約の使用を検討してください。
:- use_module(library(clpfd)).
number_digits(Number, 0, [Number]) :- Number in 0..9.
number_digits(Number, N, [Digit|Digits]) :-
Digit in 0..9,
N #= N1 + 1,
Number #= Digit*10^N + Number1,
Number1 #>= 0,
N #> 0,
number_digits(Number1, N1, Digits).
この述語は、あらゆる方向で使用できます。いずれかの引数がインスタンス化された例:
?- number_digits(215, _, Ds).
Ds = [2, 1, 5] ;
false.
?- number_digits(N, _, [4,3,2,1]).
N = 4321 ;
false.
さらに 2 つの一般的なクエリ:
?- number_digits(N, _, [A,B]).
N in 10..99,
_G2018+B#=N,
_G2018 in 10..90,
A*10#=_G2018,
A in 0..9,
B in 0..9 ;
false.
?- number_digits(N, _, Ds).
Ds = [N],
N in 0..9 ;
Ds = [_G843, _G846],
N in 0..99,
_G870+_G846#=N,
_G870 in 0..90,
_G843*10#=_G870,
_G843 in 0..9,
_G846 in 0..9 ;
etc.
clpfdに基づくさらに別のバリアントが登場します... に基づいて(#=)/3
、以下を定義します。 if_//3
n_base_digits(N、R、D) :- N #> 0, % 正の整数のみ R #> 1、% 最小ベース = 2 Ds = [D|_]、% 先頭の桁が 0 でない可能性があります D #> 0、 フレーズ(n_base_digits_aux(N、R、Ds)、Ds)。 n_base_digits_aux(N, Base, [_|Rs]) --> { D #= N mod ベース、 M #= N // ベース }, if_ (M #= 0, { Rs = [] }, n_base_digits_aux(M, Base, Rs)), [D]。
SICStus Prolog 4.3.3 を使用したクエリ:
| ?- n_base_digits(1234, 10, Ds).
Ds = [1,2,3,4] ? ;
no
逆の方法でも機能します。
| ?- n_base_digits(I,10,[1,2,3]).
I = 123 ? ;
no
上記は@mat が answer でnumber_digits/3
提案したものよりも高速であることに注意してください。
再帰を避けて、組み込みの述語を型変換に使用することもできます。
my_digits(Number, List) :-
atomic_list_concat(List, Atom),
atom_number(Atom, Number).
最初の行はリストをアトムに変換し、2 行目はこのアトムを数値に変換します。これは、その数値が渡されたものと同じ場合に true を返します。
リストを数値に変換するさらに直接的な方法があるかどうかはわかりません (そうは思わないでください..)。その場合、1 行で実現できます。
@ssBarBeeには同意しません。結局、あなたのリストを提供し、彼らの主張が正しければ、あなたは 4321 を受け取るはずです。しかし、代わりにこれを取得します:
?- my_digits(Num, [1,2,3,4]).
ERROR: is/2: Arguments are not sufficiently instantiated
で試すことができclpfd
ます:
my_digits( 0, [] ).
my_digits(N,[A|As]) :- N1 #= N/10, A #= N mod 10, my_digits(N1, As).
これを取得します:
?- my_digits(Num, [1,2,3,4]), label([Num]).
Num = -6789 ;
Num = 4321.
私はこれらすべてが非常に興味深いと思いますが、clpfd を使用したトレースは快適ではありません。
数字のリストを解析したいだけなら、次のように末尾再帰にする傾向があります。
my_digits(Num, List) :- my_digits(0, List, Num).
my_digits(Num, [], Num).
my_digits(N, [A|As], Num) :- N1 is N * 10 + A, my_digits(N1, As, Num).
これにより、次のことがわかります。
?- my_digits(Num, [1,2,3,4]).
Num = 1234 ;
false.
しかし、それは生成されません:
?- my_digits(1234, X).
ERROR: is/2: Arguments are not sufficiently instantiated
clpfd を使用せずにこれを解決していた場合、この時点で引数を調べて、別の述語を使用する傾向があります。ひどい、私は知っていますが、それが私がすることです。
my_digits(Num, List) :-
nonvar(List),
my_digits_p(0, List, Num).
my_digits(Num, List) :-
var(List),
my_digits_g(Num, ListRev),
reverse(ListRev, List).
my_digits_p(Num, [], Num).
my_digits_p(N, [A|As], Num) :- N1 is N * 10 + A, my_digits(N1, As, Num).
my_digits_g(0, []) :- !.
my_digits_g(N, [A|As]) :- A is N mod 10, N1 is floor(N / 10), my_digits_g(N1, As).
これは、数値が非変数であるかどうかを解析、チェック、または生成できます。
?- my_digits(1234, X).
X = [1, 2, 3, 4].
?- my_digits(X, [1,2,3,4]).
X = 1234 ;
false.
?- my_digits(1234, [1,2,3,4]).
true;
false.
両方の引数を変数として生成しようとすると、かなり役に立たない結果が得られます。
?- my_digits(X, Y).
X = 0,
Y = [].
したがって、my_digits に別の特殊なケースを追加して、生成を試みることができます。
my_digits(Num, List) :-
var(Num), var(List),
my_digits_g_from(0, Num, ListRev),
reverse(ListRev, List).
my_digits(Num, List) :-
nonvar(List),
my_digits_p(0, List, Num).
my_digits(Num, List) :-
var(List),
my_digits_g(Num, ListRev),
reverse(ListRev, List).
my_digits_g_from(N, N, List) :- my_digits_g(N, List).
my_digits_g_from(N, Num, List) :- succ(N, N1), my_digits_g_from(N1, Num, List).
これは大量のコードであり、 を使用しない場合に行う必要があるアクロバットの種類の良いデモンストレーションですclp(fd)
。is
残念なことに、Prolog で算術演算を行う場合、単一化されないという事実に対処する必要がありますが、その複雑さはclp(fd)
、その理由の良い証拠です。
他の誰かがよりエレガントなソリューションを持っていることを願っています!