列表我想写一个谓词,整数和数字的列表,并取得成功,如果位数包含在正确的顺序整数的数字,即:Prolog的转换整数位
?-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).
列表我想写一个谓词,整数和数字的列表,并取得成功,如果位数包含在正确的顺序整数的数字,即:Prolog的转换整数位
?-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).
我不同意@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,我会在这一点上倾向于只检查我的ARG并有单独的谓词。格罗斯,我知道,但那就是我要做的。
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)
时必须做的杂技类型。这是一个不幸的事实,当在Prolog中进行算术时,必须解决is
不统一的事实,但clp(fd)
的复杂性很好地证明了这一点。
我希望别人有更优雅的解决方案!
您也可避免递归,并使用内置谓词类型转换:
my_digits(Number, List) :-
atomic_list_concat(List, Atom),
atom_number(Atom, Number).
第一行列表转换为原子,而第二线将这个原子的数量,这将给如果该数字与传入的数字相同,则为true。
我不知道是否有更直接的方式将列表转换为数字(不这么认为),在这种情况下,它可以在一行中实现。
前面已经提出,可以考虑使用有限域约束:
:- 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.
而且两个一般性查询:
?- 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.
“数字在1..9”是否是一个错字?我期待'0..9'的数字代替。 –
是的,这是一个错字。谢谢! – mat
对于课堂作业?教授可能在寻找的东西如下所示。一般来说,你对问题陈述的分析首先应该确定特殊情况(在这种情况下是零值和负值),然后是一般情况。
: -- int_2_digits/2 ------------------------------------------------------------
:
: The public api.
:
: we've got 2 special cases here:
:
: * zero, and
: * negative numbers
:
: and, of course, the general case: a positive value.
:
: ------------------------------------------------------------------------------
int_2_digits(0 , [0]) . : zero is a special case
int_2 digits(X , ['-'|Ds]) :- : negative numbers are a special case
X < 0 , : which we handle (YMMV) by prepending the
X1 is - X , : sign and than processing the absolute value
int_2_digits(X1,Ds) . :
int_2_digits(X , Ds ) :- : the general case is a positive value
X > 0 , : just invoke the worker predicate.
int_2_digits(X,[],Ds) . :
: -- int_2_digits/3 ------------------------------------------------------------
:
: The guts of the operation.
:
: We're using an accumulator here because we compute the result right-to-left,
: from least significant digit to most significant digit. Using the accumulator
: builds the list in the correst sequence, so we don't have to reverse it at
: the end.
: ------------------------------------------------------------------------------
int_2_digits(0 , Ds , Ds) . : if we hit zero, we're done. Unify the accumulator with the result
int_2_digits(X , Ts , Ds) :- : otherwise...
D is mod(X,10) , : - get the current digit (X modulo 10)
T is div(X,10) , : - get the next value via integer division
int_2_digits(X1 , [T|Ts] , Ds) : - recurse down
. : Easy!
这里来又基于clpfd另一种变体...基于(#=)/3
和if_//3
我们定义:使用SICStus序言4.3.3
n_base_digits(N, R, Ds) :- N #> 0, % positive integers only R #> 1, % smallest base = 2 Ds = [D|_], % leading digit may not be 0 D #> 0, phrase(n_base_digits_aux(N, R, Ds), Ds). n_base_digits_aux(N, Base, [_|Rs]) --> { D #= N mod Base, M #= N // Base }, if_ (M #= 0, { Rs = [] }, n_base_digits_aux(M, Base, Rs)), [D].
查询:
| ?- n_base_digits(1234, 10, Ds).
Ds = [1,2,3,4] ? ;
no
的作品其他方式呢!
| ?- n_base_digits(I,10,[1,2,3]).
I = 123 ? ;
no
请注意以上的速度比number_digits/3
拟议by @mat in his answer。
我觉得这是比较容易:
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).
您是否尝试过什么了吗?在没有任何尝试的情况下寻求家庭作业的帮助是不好的形式。 –
尝试在调用my_digits/2之前颠倒列表,因为那么你的逻辑将适用... – ssBarBee