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すべての引数を数値にインスタンス化して呼び出す必要があります (常に呼び出されます)。

2 番目のバージョンを使用する必要がありますよね?疑問がある唯一の理由は、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

構造化プログラミングに似た私の好みの方法は、forall/2 と between/3 を組み合わせたものです。

?- 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

おそらく、一連の (float) 数値を列挙するためのより良い方法:

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.

このソリューションの利点の 1 つは、 のような浮動小数点エラーが蓄積されないことNext is This + Stepです。

于 2014-12-30T12:24:31.380 に答える