我是prolog的新手,我觉得有一个我无法理解的概念,这使我无法理解prolog中的递归概念。我试图返回S
,它是每个数字的平方和,作为用户在查询中输入的整数列表。 E.g用户输入12345
,我必须返回S = (1^2)+(2^2)+(3^2)+(4^2)+(5^2) = 55
。
在我的程序中,我理解为什么S的每个计算段都被多次打印,因为它是递归规则的一部分。但是,我不明白我将如何打印S作为最终结果。我想我可以将变量=设置为第二个规则中sos的结果,并将其作为intToList的参数添加,但似乎无法想出这一个。编译器警告S是intToList规则中的单例变量。
sos([],0).
sos([H|T],S) :-
sos(T, S1),
S is (S1 + (H * H)),
write('S is: '),write(S),nl.
intToList(0,[]).
intToList(N,[H|T]) :-
N1 is floor(N/10),
H is N mod 10,
intToList(N1,T),
sos([H|T],S).
答案 0 :(得分:1)
试试这个:
sos([],Accumulator,Accumulator).
sos([H|T],Accumulator,Result_out) :-
Square is H * H,
Accumulator1 is Accumulator + Square,
sos(T,Accumulator1,Result_out).
int_to_list(N,R) :-
atom_chars(N,Digit_Chars),
int_to_list1(Digit_Chars,Digits),
sos(Digits,0,R).
int_to_list1([],[]).
int_to_list1([Digit_Char|Digit_Chars],[Digit|Digits]) :-
atom_number(Digit_Char,Digit),
int_to_list1(Digit_Chars,Digits).
对于int_to_list
,我使用内置的atom_chars
,例如
?- atom_chars(12345,R).
R = ['1', '2', '3', '4', '5'].
然后使用典型循环使用atom_number
将每个字符转换为数字,例如
?- atom_number('2',R).
R = 2.
对于sos
我使用累加器来累积答案,然后一旦列表为空,将累加器中的值移动到结果
sos([],Accumulator,Accumulator).
请注意,累加器有不同的变量,例如
Accumulator1 is Accumulator + Square,
sos(T,Accumulator1,Result_out).
这是因为在Prolog中变量是不可变的,因此无法继续为同一变量分配新值。
以下是一些示例运行
?- int_to_list(1234,R).
R = 30.
?- int_to_list(12345,R).
R = 55.
?- int_to_list(123456,R).
R = 91.
如果您有任何问题,请在本答复的评论中提问。
答案 1 :(得分:1)
原始代码存在的问题是,您正试图在sos/2
的递归条款中处理对intToList/2
的调用。将其分解(并将intToList/2
重命名为更有意义的内容):
sosDigits(Number, SoS) :-
number_digits(Number, Digits),
sos(Digits, SoS).
这是您原来的sos/2
没有write
,这似乎工作正常:
sos([], 0).
sos([H|T], S) :-
sos(T, S1),
S is (S1 + (H * H)).
或者更好的是,使用累加器进行尾递归:
sos(Numbers, SoS) :-
sos(Numbers, 0, SoS).
sos([], SoS, SoS).
sos([X|Xs], A, SoS) :-
A1 is A + X*X,
sos(Xs, A1, SoS).
您还可以使用sos/2
和maplist/3
sumlist/2
square(X, S) :- S is X * X.
sos(Numbers, SoS) :- maplist(square, Numbers, Squares), sumlist(Squares, SoS).
您的intToList/2
需要使用累加器进行重构,以维持正确的数字顺序并摆脱对sos/2
的调用。如上所述重命名:
number_digits(Number, Digits) :-
number_digits(Number, [], Digits).
number_digits(Number, DigitsSoFar, [Number | DigitsSoFar]) :-
Number < 10.
number_digits(Number, DigitsSoFar, Digits) :-
Number >= 10,
NumberPrefix is Number div 10,
ThisDigit is Number mod 10,
number_digits(NumberPrefix, [ThisDigit | DigitsSoFar], Digits).
上述number_digits/2
也正确处理0
,因此number_digits(0, Digits)
会产生Digit = [0]
而不是Digits = []
。
您可以使用number_digits/3
构造重写-> ;
的上述实现:
number_digits(Number, DigitsSoFar, Digits) :-
( Number < 10
-> Digits = [Number | DigitsSoFar]
; NumberPrefix is Number div 10,
ThisDigit is Number mod 10,
number_digits(NumberPrefix, [ThisDigit | DigitsSoFar], Digits)
).
然后它不会留下选择点。