如何在不可更改的条件下模拟Prolog中的while循环?

时间:2014-04-05 19:22:39

标签: while-loop prolog

所以基本上我试图在Prolog中模拟一些C代码。

在Prolog中很容易模拟while循环以下是这种情况:

C代码:

int a = 1;

while(N)
{
  N--;
  a++; 
}

Prolog代码:

prolog_while(0) : !
prolog_while(N, A) :
   N1 is N -1,
   A1 is A + 1,
prolog_while(N1, A1).

一个问题是如何在不可改变的条件下模拟Prolog中的while循环?

情况如下:

int n = 1;
int a = 1;

while(1)
{
   if (N==0)
     goto while_end;
   else
    {
        N--; A++;
    }       
}

while(1)
{
   if (N==0)
     break;
   else
    {
        N--; A++;
    }       
}

我知道它有点奇怪,但基本上这些C代码是由源代码分析工具自动生成的,所以我必须处理它......

那么基本上我怎样才能在Prolog中模拟?它可行吗?

有人能给我一些帮助吗?

===================更新============

我尝试用这种方式编写一些Prolog代码,但基本上我还不知道如何处理测试条款。

main :- loop_entry(2, 1), write(N), nl, write(A), nl.

do(A, N, A1, N1) :- A1 is (A + 1), N1 is (N - 1).
test(N) :- ...                 <----- # How to write this part?
loop_entry(N, A) :-
    test(N),
    do(A, N, A1, N1),
    loop_entry(N1,A1).

4 个答案:

答案 0 :(得分:8)

在Prolog中进行无限循环的最明显方法是使用repeat/0,它看起来像这样:

while(1)
    do_something();

变为

repeat,
do_something.

真正的问题就是在Prolog中没有明显类似于gotobreak的模拟。所以我倾向于寻找这样的模式:

while(1) {
  if (test)
    break;
  do_something();
}

并将其转换为Prolog,如下所示:

loop_entry :-
  test,
  do_something,
  loop_entry.

您当然需要将本地变量作为参数添加到loop_entry/0并实现test,但这样当test失败时,循环将自然结束。

按照N和A的例子导致这种事情:

loop_entry(N, A) :-
  N > 0,
  succ(N0, N),
  succ(A, A1),
  loop_entry(N0, A1).

&#34;测试&#34;在这种情况下只是N > 0。如果它不是真的,谓词就会失败,你可以继续Prolog的生活方式。

编辑#2。如果你想要结果(N和A),那么为你想要返回的值添加额外的参数,并添加一个子句:

loop_entry(N, A, ResultN, ResultA) :-
  N > 0, !, 
  succ(N0, N),
  succ(A, A1),
  loop_entry(N0, A1, ResultN, ResultA).
loop_entry(N, A, N, A).

您可以在条件之后添加剪切,也可以在此新条款中添加反向条件。

答案 1 :(得分:3)

与你的prolog_while谓词没有什么不同:

prolog_while(N, A) :-
    ( N==0 ->
         true
    ;
         N1 is N -1,
         A1 is A + 1,
         prolog_while(N1, A1)
    ).

但是很可能你希望A的最终值可以被这个谓词的调用者使用,所以你必须通过一个额外的参数返回它:

prolog_while(N, A, AFinal) :-
    ( N==0 ->
         AFinal = A
    ;
         N1 is N -1,
         A1 is A + 1,
         prolog_while(N1, A1, AFinal)
    ).

答案 2 :(得分:1)

来自Logtalk标准库:

:- meta_predicate(whiledo(0, 0)).
whiledo(Condition, Action) :-
    (   call(Condition) ->
        \+ \+ call(Action),
        whiledo(Condition, Action)
    ;   true
    ).

对于其他传统的循环结构,请参阅: https://github.com/LogtalkDotOrg/logtalk3/blob/master/library/loopp.lgt https://github.com/LogtalkDotOrg/logtalk3/blob/master/library/loop.lgt

答案 3 :(得分:1)

为了在Prolog中实现while循环,我为命令性语言编写了a small interpreter

使用此解释器,可以这样编写while循环:

:- initialization(main).
:- set_prolog_flag('double_quotes','chars').

main :-
    imperative_statements((
        A=1,
        N=0,
        while(A<50,(
            A=A+2,
            N=N-1
        ))
        D = increment_var(1)
    )),
    writeln(A),
    writeln(N),
    writeln(D).

increment_var(A,B) :-
    imperative_statements((
        B=A,
        while(B<50,(
            B=B*2
        ))
    )).

print(A,true) :-
    writeln(A).

imperative_statements(A) :-
    term_variables(A,Names),
    length(Names,L),
    length(Input,L),
    length(Output,L),
    set_var(A,Names,Input,Output),
    Names=Output.

set_var(A,Names,Input) :-
    length(Input,L),
    length(Output,L),
    set_var(A,Names,Input,Output),
    Names=Output.

set_var((A,B),Var_names,Input,Output) :-
        set_var(A,Var_names,Input,Output1),
        set_var(B,Var_names,Output1,Output).

set_var(Name=Value,Var_names,Input,Output) :-
    get_var(Value,[Var_names,Input],Value1),
    set_var_(Name=Value1,Var_names,Input,Output).

set_var_(_,[],[],[]).
set_var_(Name=Value1,[Name1|Name2],[Var1|Var2],[Output1|Output2]) :-
    (Name==Name1,Output1=Value1;
    Name \== Name1,Output1=Var1),
    set_var_(Name=Value1,Name2,Var2,Output2).

set_var(while(A,B),Names,Vars,Result) :-
    get_var(A,[Names,Vars],A1),
    (((A1==true)->(set_var(B,Names,Vars,Result1),set_var(while(A,B),Names,Result1,Result)));
    A1==false,Vars=Result).

get_var(Name,[[Name1],[Var1]],Output) :-
    var(Name),Name==Name1,
    Output=Var1.
get_var(Name,[[Name1|Name2],[Var1|Var2]],Output) :-
    var(Name),(Name==Name1,get_var(Name,[[Name1],[Var1]],Output);
    Name \== Name1,get_var(Name,[Name2,Var2],Output)).

get_var([],_,[]).
get_var([Name1|Name2],Vars,[Name3|Name4]) :-
    get_var(Name1,Vars,Name3),
    get_var(Name2,Vars,Name4).

get_var(Name,_,Name) :-
    number(Name);atom(Name).
get_var(A+B,Vars,Output) :-
    get_var(A,Vars,A1),
    get_var(B,Vars,B1),
    Output is A1+B1.
get_var(A-B,Vars,Output) :-
    get_var(A,Vars,A1),
    get_var(B,Vars,B1),
    Output is A1-B1.
get_var(A*B,Vars,Output) :-
    get_var(A,Vars,A1),
    get_var(B,Vars,B1),
    Output is A1*B1.
get_var(A/B,Vars,Output) :-
    get_var(A,Vars,A1),
    get_var(B,Vars,B1),
    Output is A1/B1.
get_var(A**B,Vars,Output) :-
    get_var(A,Vars,A1),
    get_var(B,Vars,B1),
    Output is A1**B1.

get_var((A,B),Vars,Result) :-
    get_var([A,B],Vars,[A1,B1]),
    (A1,B1,Result=true;([A1,B1]=[true,false];[A1,B1]=[false,true]),Result=false).

get_var((A;B),Vars,Result) :-
    (get_var(A,Vars,A1),call(A1);
    get_var(B,Vars,B1),call(B1)) -> (Result = true);
    (get_var(A,Vars,A1),A1=false,Result=false).

get_var(A<B,Vars,Result) :-
    get_var(B>A,Vars,Result).
get_var(A>B,Vars,Result) :-
    %comparison of variables
    get_var([A,B],Vars,[A1,B1]),
    (A1>B1,Result=true;A1<B1,Result=false).

get_var(A==B,Vars,Result) :-
    %comparison of variables
    get_var([A,B],Vars,[A1,B1]),
    (A1==B1,Result=true;A1\=B1,Result=false).

get_var(Input,Vars,Output1) :-
    (\+number(Input)),
    Input =.. [Name|Params],
    \+member(Name,['=',==,'->',not,'[|]',',',';',+,-,*,/,**,^,writeln]),
    length(Params,Params_length),
    Params_length > 0,
    get_var(Params,Vars,Params1),
    append([Name|Params1],[Output1],Input0),
    Input1 =.. Input0,
    call(Input1).