2016-04-02 3 views
0

У меня есть следующий код пролога. Ссылка предикат относится к другому файлу, содержащему различные ссылки, такие как:Управление петлей Prolog не работает должным образом

link(b,brown,j) 

Я использую предикат члена пытаться контролировать зацикливание в этом маршруте программе. Идея заключается в том, что раньше я был на определенной позиции, программа не будет пытаться спуститься по этому маршруту.

Однако, когда я пытаюсь проследить программу, чтобы увидеть, где она идет не так, когда она проверяет, является ли позиция членом в списке позиций, первая позиция уже находится в списке, поэтому программа всегда пытается другой маршрут после этого момента, когда он не должен. Кто-нибудь знает, как это исправить?

member(X,[X|_]). 
member(X,[_|Xs]):- member(X,Xs). 

route(X,X,[X],_). 
route(X,Z,[X|Path],Positions):- 
    link(X,Colour,Y), 
    \+member([Y,Colour],Positions),    
    route(Y,Z,Path,[[Y,Colour]|Positions]), 
    !. 
+0

Пожалуйста, не хулиганить на ваш вопрос. Если есть проблема с этим сообщением, вы можете предупредить модератора, подняв пользовательский флаг. – Tunaki

+0

Вы не имеете права удалять свой собственный контент после размещения. Пожалуйста, воздержитесь от дальнейших попыток самоуважения. – Magisch

ответ

3

Некоторые незначительные замечания во-первых: вам не нужно это разрезать вообще. Если вы действительно хотите ограничить предикат точно одним ответом, сделайте это сверху, используя once/1. Это не только концептуально чище, но и более эффективно.

Другая проблема, с которой вы столкнулись, связана с небезопасным отрицанием Пролога. Если вы случайно, как и вы, сдадите цель, которая является слишком общей, отрицание всегда будет терпеть неудачу. Другими словами: отрицание в Prolog является следующим. Есть два выхода: либо создать ошибку для таких случаев, либо просто использовать более точное определение, например, non_member/2.

Давайте посмотрим, что случилось бы с non_member/2 на месте:

link(b,brown,j). 

route(X,X,[X],_). 
route(X,Z,[X|Path],Positions):- 
    link(X,Colour,Y), 
    % \+member([Y,Colour],Positions), 
    non_member([Y,Colour],Positions), 
    route(Y,Z,Path,[[Y,Colour]|Positions]). 

non_member(E, Es) :- 
    maplist(dif(E), Es). 

| ?- route(X,Y,Path,Rs). 
    Y = X, Path = [X] 
; X = b, Y = j, Path = "bj", Rs = [] 
; X = b, Y = j, Path = "bj", Rs = [_A], 
    dif([j,brown],_A) 
; X = b, Y = j, Path = "bj", Rs = [_A,_B], 
    dif([j,brown],_A), 
    dif([j,brown],_B) 
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C], 
    dif([j,brown],_A), 
    dif([j,brown],_B), 
    dif([j,brown],_C) 
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D], 
    dif([j,brown],_A), 
    dif([j,brown],_B), 
    dif([j,brown],_C), 
    dif([j,brown],_D) 
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D,_E], 
    dif([j,brown],_A), 
    dif([j,brown],_B), 
    dif([j,brown],_C), 
    dif([j,brown],_D), 
    dif([j,brown],_E) 
; ... 

Таким образом, все ответы описывают один и тот же Path = "bj" (короткая форма для [b,j]). Но последний аргумент теперь представляет собой список элементов, которые должны быть разными для [j,brown]. Так что лучше было бы:

route(X, Y, Path) :- 
    route(X, Y, Path, []). 

А вот альтернативное определение повторного path/4. Я не совсем уверен, что вы подразумеваете под этими цветами. Тем не менее:

clink(X-_, Y-Color) :- 
    link(X, Color, Y). 

route(X, Y, Path) :- 
    path(clink, Path, X-none, Y-_). 

или даже короче при использовании library(lambda):

route(X, Y, Path) :- 
    path(\ (Xl,_)^(Yl^C)^clink(Xl,C,Yl), Path, X-none, Y-_). 
Смежные вопросы