枚举序列和if-then-else

时间:2013-09-05 08:58:48

标签: loops prolog

模仿一个简单的循环:

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必须(并且将始终)调用所有参数实例化为数字。

我应该使用第二个版本,对吗?唯一的理由是,在介绍性的Prolog材料中几乎没有if-then-else结构,我无法弄清楚为什么(Learn Prolog Now!,例如,否则是一个很好的介绍性材料,没有甚至提到它!)。与此同时,每个方向都会随意飞行。

感谢您的帮助!

3 个答案:

答案 0 :(得分: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的情况下,您可以使用标准库中的/ 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的介绍性文章。

答案 1 :(得分: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.

答案 2 :(得分: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这样的浮点错误。