Prolog 人工智能语言中文论坛---打造优质Prolog学习交流园地
Would you like to react to this message? Create an account in a few clicks or log in to continue.
Prolog 人工智能语言中文论坛---打造优质Prolog学习交流园地

一个供Prolog爱好者学习与交流的地方


您没有登录。 请登录注册

模拟一般程序语言的for循环---for谓词

向下  留言 [第1页/共1页]

1模拟一般程序语言的for循环---for谓词 Empty 模拟一般程序语言的for循环---for谓词 周三 十月 17, 2012 5:09 pm

Mercury Liao


Admin

for(:Goal, +Index_From, +Index_To, +Index_Step)

模拟一般程序语言的for循环。以C语言为例,此for谓词可表述为

for(i=Index_From; i<=Index_To; i+=Index_Step)
Goal;

如果Index_Step为负,则是表述为

for(i=Index_From; i>=Index_To; i+=Index_Step)
Goal;

Index_Step省略时,默认为1。


代码:
for(Goal, Index_From, Index_To) :- for(Goal, Index_From, Index_To, 1).

for(Goal, Index_From, Index_To, Index_Step) :-
  nonvar(Goal),
  (Index_From =< Index_To -> Goal =.. X, replace(X, 2, Index_From, Y), replace(Y, 3, Return, M),
  Z =.. M, (Z -> replace(Y, 4, Return, W), V =.. W, Next_Index is Index_From + Index_Step, for(V, Next_Index, Index_To, Index_Step);
  arg(3, Goal, A), arg(2, Goal, A)); arg(3, Goal, A), arg(2, Goal, A)).

replace(List, Index, With, ListOut) :-
  Idx is Index - 1, length(Before,Idx),
  append(Before, [_Discard|Rest], List),
  append(Before, [With|Rest], ListOut).

Goal的编写有规定的格式:

代码:
goal_name(Index, Static_Return, Static_Initial, ......).

前3个参数为保留参数,规定第1个参数是传入的Index值,每迭代一次变化一次;
第2个参数Static_Return为静态变量最终回传值,当静态变量多于一个时可用List表述;
第3个变量Static_Initial为静态变量初始值;
其后的"......"可自行增加传入或传出的变量,个数不限。

注意:
1. Static_Return与Static_Initial必须一一对应,也就是说如果为List形态,List内的元素个数须一样多。
2. 如果想传出的变量在Goal的多次选代过程中一旦被绑定后不会再需要被绑定为其他值,可用"......"自行增加变量传出(这种情形较少见);
但若被绑定后还有可能再被绑定为其他值,则必须用Static_Return传出(一般应该都是这种情况)。


如果想产生C语言里的break功能,则在Goal编写时,在想break的地方加入false。
这也意谓着…Goal一定是true的(false的话会被视为跳出循环),
如果确实想传出"false"信息而非break,可利用Static_Return增设一个变量传出。

使用break时还要特别注意:
一旦break,当次的迭代对静态变量的影响忽略不计,这点和一般语言的break不太一样。
例如goal(I, C1, C) :- C1 is C + I, (I >= 5 -> false; true).
当执行查询for(goal(I, C1, 0), 1, 5)时,C1传回10(因为1 + 2 + 3 + 4 = 10),
可以看到,虽然goal的编写上是先执行加总,再透过检查I决定是否break,很容易被误认为5也被加总进C1中,
但其实break的当次迭代(I = 5这次)视为无效,所以C1只从1加到4。



例:

假设编写5个Goal谓词如下

代码:
wri(I, _, _) :- write(I), nl.    % 将I的值印出来

sum(I, Static_Return, Static) :- Static_Return is Static + I.    % 将I的值加总回传

formula_sum(I, Static_Return, Static) :- Static_Return = Static + I.    % 将I的值加总并以公式形式表述

calculate(I, [Sumproduct, Sum_of_square], [Spt, Sos], X, Y) :-
  nth1(I, X, A), nth1(I, Y, B), Sumproduct is Spt + A * B, Sum_of_square is Sos + A * A.    % 将X与Y两个List的项对应相乘并加总得到Sumproduct;将X各项取平方并加总得到Sum_of_square
 
calculate_for_N_is_2(I, [Sumproduct, Sum_of_square], [Spt, Sos], X, Y) :-
  I = 3 -> false; nth1(I, X, A), nth1(I, Y, B), Sumproduct is Spt + A * B, Sum_of_square is Sos + A * A.    % 同前,但I=3时break跳出循环

49 ?- for(wri(I, _, _), 1, 5, 2).
1
3
5
true.


47 ?- for(sum(I, Answer, 0), 1, 5).
Answer = 15.


48 ?- for(formula_sum(I, Formula, 0), 1, 5).
Formula = 0+1+2+3+4+5.


53 ?- for(calculate(I, [Sumproduct, Sum_of_square], [0, 0], [4, 10, 3], [2, 5, 7]), 1, 3).
Sumproduct = 79,
Sum_of_square = 125.


58 ?- for(calculate_for_N_is_2(I, [Sumproduct, Sum_of_square], [0, 0], [4, 10, 3], [2, 5, 7]), 1, 3).
Sumproduct = 58,
Sum_of_square = 116.



由Mercury Liao于周三 十月 31, 2012 8:24 am进行了最后一次编辑,总共编辑了5次

http://prolog.longluntan.net

Mercury Liao


Admin

对于不需回传变量的循环,可使用内建谓词forall/2:

31 ?- forall(between(1,9,X), (write(X), nl)).
1
2
3
4
5
6
7
8
9
true.

http://prolog.longluntan.net

返回页首  留言 [第1页/共1页]

您在这个论坛的权限:
不能在这个论坛回复主题