SWI Prolog if语句,它们如何工作?生成一个简单的网格

时间:2018-02-11 21:48:44

标签: prolog

我意识到我已经从原始代码中删除了if语句,这些语句无助于提高可读性和问题清晰度。只需跳过解答,了解它们如何使用小型示例程序。

要在Prolog中使用if语句了解更复杂的程序,我正在创建一个简单的平台游戏,它会生成一些对象并将它们放在网格中。首先,我试图创建一个简单的“世界”,试图在prolog中尝试生成东西。计划是创建一个包含10000个项目的50个列表的网格,这真的不应该那么复杂但是我无法让if语句工作,因为我得到的印象是我从根本上误解了它们是如何工作与我认为他们的工作方式。如果不满足条件,则不调用if语句,但使用空变量调用整个谓词,并且不实例化评估。

  1. 创建一个具有X和Y轴且限制为的简单累加器 他们在失败谓词之前走了多远。
  2. 如果已达到Y行数,则终止
  3. 创建一个新的[id,point(X,Y),Image],稍后用
  4. 填充
  5. 如果X =行的结尾,X为0,否则创建下一个点
  6. 代码:

    generate(WorldList) :- generate_world(WorldList,0,_,10000,0,_,50).
    
    generate_world([H|T],X,_,XEnd,Y,_,YEnd) :-
        %Y has been filled with 50 rows, end recursion
        not(Y > YEnd),
        %iterate X by 1, store in XNew
        XNew is X + 1,  
        %create a new [id,point(X,Y), Image]
        H = [XNew,point(_,_)],
        %if X has reached 10k, add 1 to Y and create a new row
        X = XEnd -> YNew is Y + 1, 
        generate_world(T,0,_,XEnd,YNew,_,YEnd);
        %continue adding items to current row Y
        generate_world(T,XNew,_,XEnd,Y,_,YEnd).
    generate_world([],_,_,_,_,_,_).
    

    我做了一些明显错误的事情,或者你应该如何使用prolog条件声明,甚至可以像这样使用它们?

    我期望它工作的方式是评估一个术语,然后执行以下OR的左边的OR,如果它是真的,或者如果它是假的则执行。发生这种情况,但我不明白为什么再次调用整个谓词,因为它也会清空正在评估的变量。我的大脑疼。

    文档说的是什么:http://www.swi-prolog.org/pldoc/man?predicate=-%3E/2

    @damianodamiano确定了问题,prolog中的if语句需要被()标记包围。我仍然想要更详细地解释他们如何在选择点,回溯和其他Prolog特定的事情上工作,我甚至可能都不知道。

3 个答案:

答案 0 :(得分:1)

你的谓词一运行就会停止,因为在not(By > YEnd)中,By没有实例化(注意By也是一个单例变量,每个单例变量都没用,可以驱动错误)。这里我发布了两个实现,第一个没有if语句(个人更喜欢),第二个用if语句(我将22视为简洁...)。< / p>

首次实施:

generateList(L):-
    generateWL(L,0,2,0,2).
generateWL([],0,_,Y,Y). %you can add a ! here
generateWL(L,MaxX,MaxX,R,MaxR):- %you can add a ! here
    R1 is R+1,
    generateWL(L,0,MaxX,R1,MaxR).
generateWL([H|T],X,MaxX,R,MaxR):-
    X < MaxX,
    R < MaxR,
    X1 is X+1,
    H = [X1,point(X1,R)],
    generateWL(T,X1,MaxX,R,MaxR).

?- generateList(WL).
WL = [[1, point(1, 0)], [2, point(2, 0)], [1, point(1, 1)], [2, point(2, 1)]]
false

如果您想阻止回溯,只需添加我已注释的两个剪辑。

第二次实施

generateList2(L):-
    generateWLIf(L,0,2,0,2).

generateWLIf([H|T],X,MaxX,R,MaxR):-
    (   X < MaxX, R < MaxR ->    
        X1 is X+1,
        H = [X1,point(X1,R)],
        generateWL(T,X1,MaxX,R,MaxR)
    ;   X = MaxX, R < MaxR ->  
        R1 is R+1,
        generateWL([H|T],0,MaxX,R1,MaxR)
    ;   R = MaxR ->  T = []).

?- generateList2(WL).
WL = [[1, point(1, 0)], [2, point(2, 0)], [1, point(1, 1)], [2, point(2, 1)]]

答案 1 :(得分:1)

(继续评论)

  

我期望[条件陈述]工作的方式是一个术语   评估,然后执行以下OR左侧的操作,如果是的话   是的,如果它是假的,那就是正确的。会发生这种情况,但我不明白   为什么整个谓词再次被调用,因为它也清空了   正在评估的变量。

你可能意味着它回溯了,原因是比较not(Y > YEnd)最终失败,并且没有else子句(如果有的话也没有)。

此外,您的基本情况没有意义,因为列表输出不输入。并且您希望与XNew而不是X进行比较。

generate(WorldList) :-
  generate_world(WorldList,1,10000,1,50).

generate_world(T,X,XEnd,Y,YEnd) :-
  ( Y = YEnd ->
    T = []
  ; T = [point(X,Y)|Rest], XNew is X + 1,
    ( XNew = XEnd -> YNew is Y + 1,
      generate_world(Rest,1,XEnd,YNew,YEnd)
    ; generate_world(Rest,XNew,XEnd,Y,YEnd) ) ).

这似乎与你所描述的一样,但它不是好的设计。现在你必须一直传递这个巨大的列表,更新一个位置意味着解构列表。

你的问题:

  

我正在创建一个生成一些对象的简单平台游戏   将它们放在网格中。首先,我试图创造一个简单的世界&#39;   想要尝试在prolog中生成东西。计划是   创建一个包含10000个项目的50个列表的网格

通过使用谓词location/3(例如),参数是坐标和内容,在Prolog中可以更好地解决

location(1,1,something).
location(1,2,something).
location(1,3,somethingelse).
...

此谓词是使用assert/3动态创建的。

答案 2 :(得分:0)

这是基于我对ISO-prolog的理解以及给出的其他答案,归结为if then else在Prolog中如何运作的本质。

if谓词->会强制评估按()分组的周围复杂术语。外括号将if语句标识为( if -> then ; else ),其中ifthenelse是要评估的术语形式的每个目标,返回{{1 }或yes,也按no(分组。是否调用)then,由OR运算符else分隔,取决于{{1}所表示的评估字词的;yes结果}}。外部分组是绝对必要的,而内部分组是可选的,但我认为最好添加它们是好的,因为你可以将另一个no语句嵌套为{{1}所包围的术语在第一个结果中,这可能会产生不需要的结果并使代码更难以阅读,任何未分组的嵌套if都会将右侧标识为if

创建选择点,其中存在可以具有多个可能答案的变量作为所提出目标的可能解决方案。这意味着在()范围内,如果一个术语可以多种方式满足,Prolog将尝试将该目标作为单独的目标来满足,然后使用该结果来确定周围术语的结果。如果目标失败,它的行为就像普通代码一样,并没有试图进一步正确地实现目标。

如果选择点位于整个;语句部分之前,则将再次检查整个部分。

澄清这个想法的示例程序。

else

if

的输出
if