Duc*_*Hai 5 list prolog digit clpfd
我想编写一个整数和数字列表的谓词,如果 Digits 以正确的顺序包含整数的数字,则成功,即:
?-digit_lists( Num, [1,2,3,4] ).
[Num == 1234].
Run Code Online (Sandbox Code Playgroud)
这是我到目前为止所拥有的:
my_digits( 0, [] ).
my_digits(N,[A|As]) :- N1 is floor(N/10), A is N mod 10, my_digits(N1, As).
Run Code Online (Sandbox Code Playgroud)
小智 5
我认为这更容易:
numToList(NUM,[LIST|[]]):-
NUM < 10,
LIST is NUM,
!.
numToList(NUM,LIST):-
P is NUM // 10,
numToList(P,LIST1),
END is (NUM mod 10),
append(LIST1,[END] ,LIST).
Run Code Online (Sandbox Code Playgroud)
我不同意@ssBarBee。毕竟,如果你提供了你的清单并且他们的指控是正确的,你应该得到 4321;但你会得到这个:
?- my_digits(Num, [1,2,3,4]).
ERROR: is/2: Arguments are not sufficiently instantiated
Run Code Online (Sandbox Code Playgroud)
我们可以尝试一下clpfd:
my_digits( 0, [] ).
my_digits(N,[A|As]) :- N1 #= N/10, A #= N mod 10, my_digits(N1, As).
Run Code Online (Sandbox Code Playgroud)
我们得到这个:
?- my_digits(Num, [1,2,3,4]), label([Num]).
Num = -6789 ;
Num = 4321.
Run Code Online (Sandbox Code Playgroud)
我觉得这一切都很奇怪,但是用 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).
Run Code Online (Sandbox Code Playgroud)
这给了我们:
?- my_digits(Num, [1,2,3,4]).
Num = 1234 ;
false.
Run Code Online (Sandbox Code Playgroud)
但它不会生成:
?- my_digits(1234, X).
ERROR: is/2: Arguments are not sufficiently instantiated
Run Code Online (Sandbox Code Playgroud)
如果我在没有 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).
Run Code Online (Sandbox Code Playgroud)
这可以解析或检查,或生成数字是否为非变量:
?- 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.
Run Code Online (Sandbox Code Playgroud)
如果您尝试使用两个参数作为变量来生成,您将得到一个非常无用的结果:
?- my_digits(X, Y).
X = 0,
Y = [].
Run Code Online (Sandbox Code Playgroud)
因此,我们可以尝试通过向 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).
Run Code Online (Sandbox Code Playgroud)
这是很多代码,很好地演示了不使用clp(fd). 不幸的是,当在 Prolog 中进行算术时,我们必须解决is不统一的事实,但 的复杂性clp(fd)很好地证明了原因。
我希望其他人有更优雅的解决方案!