while(:Condition, :Goal)
模拟一般程序语言的while循环。以C语言为例,此while谓词可表述为
while(Condition){
____Goal;
};
Goal的编写有规定的格式:
前2个参数为保留参数,
规定第1个参数Static_Return为静态变量最终回传值,当静态变量多于一个时可用List表述;
规定第2个参数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不太一样。
例子可以参考for谓词的break用法。
例:
假设编写Goal谓词如下
12 ?- while(C1 =< -1, add([C1, D1], [0, 0])).
C1 = D1, D1 = 0.
13 ?- dowhile(add([C1, D1], [0, 0]), C1 =< -1).
C1 = D1, D1 = 1.
C1 =< -1一开始就不成立,所以while/2一次都不执行(先检查,检查不通过则不执行),
但dowhile/2至少会执行一次(先执行,执行完后才检查是否再执行)。
注意到这里,虽然dowhile/2尚未开始执行add,
看起来C1应是个变量,无法判断C1 =< -1是否成立。
但实际操作中,一开始C1会被视为有初始值0(由add的第二个参数[0, 0]给出的),
所以是可以判断C1 =< -1是否成立的。
模拟一般程序语言的while循环。以C语言为例,此while谓词可表述为
while(Condition){
____Goal;
};
- 代码:
while(Condition, Goal) :-
nonvar(Condition), nonvar(Goal),
Goal =.. X, nth1(2, X, Ori), copy_term((Condition, Ori), (CC, Return)),
nth1(3, X, Ini), Ini = Return,
(CC -> replace(X, 2, Return2, M), Z =.. M,
(Z -> replace(X, 3, Return2, W), V =.. W, while(Condition, V); Ori = Ini);
Ori = Ini).
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(Static_Return, Static_Initial, ......).
前2个参数为保留参数,
规定第1个参数Static_Return为静态变量最终回传值,当静态变量多于一个时可用List表述;
规定第2个参数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不太一样。
例子可以参考for谓词的break用法。
例:
假设编写Goal谓词如下
- 代码:
add([C1, D1], [C, D]) :- D1 is D + 1, C1 is C + D1.
12 ?- while(C1 =< -1, add([C1, D1], [0, 0])).
C1 = D1, D1 = 0.
13 ?- dowhile(add([C1, D1], [0, 0]), C1 =< -1).
C1 = D1, D1 = 1.
C1 =< -1一开始就不成立,所以while/2一次都不执行(先检查,检查不通过则不执行),
但dowhile/2至少会执行一次(先执行,执行完后才检查是否再执行)。
注意到这里,虽然dowhile/2尚未开始执行add,
看起来C1应是个变量,无法判断C1 =< -1是否成立。
但实际操作中,一开始C1会被视为有初始值0(由add的第二个参数[0, 0]给出的),
所以是可以判断C1 =< -1是否成立的。