【问题标题】:How Can I simulate a while loop in Prolog with unchangeable conditions?如何在 Prolog 中模拟条件不变的 while 循环?
【发布时间】:2014-04-05 19:22:39
【问题描述】:

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

在Prolog中很容易模拟while循环是这样的:

C 代码:

int a = 1;

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

序言代码:

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代码,但基本上还是不知道怎么处理test子句。

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).

【问题讨论】:

  • 您希望main/1 能够如何工作?变量NA 不会在任何地方实例化,所以write/1 最终只会写入匿名变量的名称——类似于_G978。更重要的是,剪切运算符! 并不意味着false,并且不像“break”语句那样起作用,因此N = 0 -&gt; ! 不会导致test/1 失败。

标签: while-loop prolog


【解决方案1】:

在 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).

本例中的“测试”就是N &gt; 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).

您可以在条件之后添加一个剪切,或者将相反的条件放在这个新子句中。

【讨论】:

  • 嗨,Daniel,谢谢您的回答,我尝试按照您的回答编写示例序言代码,但我仍然不知道如何处理 test 子句.. .
  • 嗨丹尼尔,谢谢你的回复,但基本上我怎样才能得到结果(我的意思是最终的A和N),因为当N = 0时,N>0会失败并且之前的所有递归loop_entry 的调用将全部失败,然后 prolog 程序将失败....
  • 对不起,其实我对Prolog不是很熟悉,如果我问了一个愚蠢的问题,请原谅我......
  • @computereasy 我再次编辑了答案。 :) 保持信念,你会到达那里。
  • @Lori 我不知道。我不这么认为,因为这是消除尾调用的一个非常明显的候选者,而且我认为主要的实现都进行了尾调用消除。但我不是 100% 确定。
【解决方案2】:

与您的 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)
    ).

【讨论】:

    【解决方案3】:

    来自 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

    【讨论】:

    • Z = 1, whiledo(Z &lt; 4,Z=Z+1) 似乎总是失败。是否有任何文档说明如何使用此谓词?
    • @AndersonGreen 并不是说​​目标Z=Z+1(或Z is Z+1,可能是你想写的)总是错误的。因此,上述定义在这种情况下不可用。但是请参阅我的答案中链接中的其他“循环”元谓词。例如。 loop::forto(Z, 1, 4, write(Z)) 会写成1234
    【解决方案4】:

    为了在 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).
    

    【讨论】:

    • 谢谢安德森。这对我来说很有意义。
    猜你喜欢
    • 2012-12-03
    • 2010-10-19
    • 2014-06-26
    • 1970-01-01
    • 2013-05-05
    • 2013-11-08
    • 1970-01-01
    • 2015-02-27
    相关资源
    最近更新 更多