1

要模拟这样的简单循环:

start = something; 
incr = something_else;
end = yet_something_else; /* all three are numerical values, int or float */
while (start <= end) {
    /* do something for its side effect, for example: */
    printf("%d %d\n", start, start*start);
    start += incr;
}

我可以写:

loop1(Start, End, _Incr) :-
    Start > End, !. % yes, the cut is necessary!
loop1(Start, End, Incr) :-
    Start =< End,
    /* do something for its side effect, for example */
    format('~d ~d~n', [Start, Start*Start]),
    Next is Start + Incr,
    loop1(Next, End, Incr).

或者:

loop2(Start, End, Incr) :-
    (   Start =< End
    ->  format('~d ~d~n, [Start, Start*Start]),
        Next is Start + Incr,
        loop2(Next, End, Incr)
    ;   true
    ).

loop/3必须(并且总是会)调用实例化为数字的所有参数。

我应该使用第二个版本,对吧?存在疑问的唯一原因是 if-then-else 结构在 Prolog 介绍材料中几乎没有,我不知道为什么(例如,立即学习 Prolog!,否则一个很好的介绍材料,不甚至不提!)。与此同时,每一个方向都有随意飞舞的切口。

谢谢您的帮助!

4

3 回答 3

1

我不知道他们为什么不提。所有实用的程序员都使用它。

但是如果用失败驱动的循环重写你的代码,我们可以避免使用 cut/if-then-else。

loop(From, To, Incr, Val) :- 
  From =< To,
  ( Val = From
  ; Next is From + Incr,
    loop(Next, To, Incr, Val)
  ).

print_squares(Start, End, Incr) :-
  loop(Start, End, Incr, Val),
  Square is Val * Val,
  format('~d ~d~n', [Val, Square]),
  fail
  ; 
  true.

在 Incr = 1 的情况下,您可以使用标准库中的 between/3 :

print_squares(Start, End) :-
  between(Start, End, Val),
  Square is Val * Val,
  format('~d ~d~n', [Val, Square]),
  fail
  ; 
  true.

如果你懂俄语或可以翻译它,我可以推荐我的书http://sourceforge.net/projects/uranium-test/files/prolog/speed_prolog.pdf/download作为 Prolog 的入门数学。

于 2013-09-05T11:17:44.630 回答
1

我喜欢的类似于结构化编程的方式是介于/3 和 forall/2 之间。

?- forall(between(1,3,N), writeln(N)).

这是一个来自 ICLP2013 竞赛的“应用”示例:

icecream(N) :-
    loop(N, top(N)),
    left, loop(N+1, center), nl,
    loop(N+1, bottom(N)).

:- meta_predicate loop(+, 1).

loop(XH, PR) :-
    H is XH,
    forall(between(1, H, I), call(PR, I)).

top(N, I) :-
    left, spc(N-I+1), pop,
    (   I > 1
    ->  pop,
        spc(2*(I-2)),
        pcl
    ;   true
    ),
    pcl, nl.

bottom(N, I) :-
    left, spc(I-1), put(\), spc(2*(N-I+1)), put(/), nl.

center(_) :- put(/), put(\).

left :- spc(4).
pop :- put(0'().
pcl :- put(0')).
spc(Ex) :- V is Ex, forall(between(1, V, _), put(0' )).

产量

2 ?- [icecream].
% icecream compiled 0.00 sec, 10 clauses
true.

3 ?- icecream(5).
         ()
        (())
       ((  ))
      ((    ))
     ((      ))
    /\/\/\/\/\/\
    \          /
     \        /
      \      /
       \    /
        \  /
         \/
true.
于 2013-09-05T14:08:04.473 回答
0

可能是枚举(浮点)数字序列的更好方法:

sequence(First, Step, Last, R) :-
    D is Last - First,
    sign(Step) =:= sign(D),
    N is floor(D / Step),
    between(0, N, X),
    R is First + X * Step.

此解决方案的优点之一是它不会像Next is This + Step.

于 2014-12-30T12:24:31.380 回答