2009-07-08 8 views
4

나는 프롤로그에서 findall 선언문을 구현하려고합니다. (예, 내장되어 있다는 것을 알고 있습니다. 어떤 이유PROLOG 규칙은 첫 번째 일치 만 반환합니다.

my_findall(N,P,Pred,L) :- Pred, not(new(N,P)), !, assert(new(N,P)), my_findall(N1,P1,Pred,L1), L=[N,P,L1], retract(new(N,P)). 
my_findall(_,_,_, []). 

단지 저 첫번째 솔루션을 제공하고 my_findall 두 번째 전화가 실패하는 경우로서,이 정지 다음과 같이

그것은이 기입된다. 내가 이해하는 바와 같이, 후퇴 메커니즘은 Pred (N, P) 호출에 대한 모든 옵션을 포함해야하는 모든 가능한 옵션을 거쳐야하므로 두 번째 호출이 첫 번째 시도에서 실패해야한다고해도 (첫 번째 옵션은 Pred에 대해 이미 시도했습니다. 주장 된), 그것을 포기하고 my_findall ((,), _, [])로 가기 전에 먼저 다른 모든 옵션을 시도해야합니다.

이것이 작동하는 방식이 아니라면 솔루션을 완전히 다시 작성하지 않고 이러한 종류의 동작을 강제하는 방법이 있습니까?

+0

어떤 프롤로그 인터프리터를 사용하고 있습니까? – liori

+0

내장 된 findall은 findall/3 및 findall/4입니다. 어느 것을 구현하려고합니까? – Kaarel

답변

5

귀하의 Pred는 언 바운드 변수를 포함합니다. 첫 번째 반복에서 Pred를 호출하면 이러한 변수가 첫 번째 가능한 값에 바인딩됩니다. 재귀 적 단계에서 Pred는 이미 바운드 변수를 가지고 있으며 값을 변경할 수 없습니다. 그래서 ...이 솔루션은 작동하지 않습니다.

첫 번째 수준 (전화 : SWI - 프롤로그에서

추적 (나는 몇 가지 이유에 대한 항목/2/2 새 이름을 변경했다) (my_findall (A, B, 구성원 (P는 A, B), [p (1,2), p (3,4)]), L).

Call: (7) my_findall(_G819, _G820, member(p(_G819, _G820), [p(1, 2), p(3, 4)]), _G840) ? creep 
    Call: (8) lists:member(p(_G819, _G820), [p(1, 2), p(3, 4)]) ? creep 
    Exit: (8) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep 

우리는 p (A, B) = p (1,2)를 얻었다. 이 점 A는 1 바인딩에서, B는 2

^ Call: (8) not(item(1, 2)) ? creep 
    Call: (9) item(1, 2) ? creep 
    Fail: (9) item(1, 2) ? creep 
^ Exit: (8) not(item(1, 2)) ? creep 

확인에 결합 된 데이터베이스에 어떠한 항목 (1,2)이 없다.

^ Call: (8) assert(item(1, 2)) ? creep 
^ Exit: (8) assert(item(1, 2)) ? creep 

지금 항목 (1,2)이 참입니다. 재귀 호출 :

Call: (9) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep 
          ^^^^^^^ 

밑줄 친 부분을 참조하십시오

Call: (8) my_findall(_L215, _L216, member(p(1, 2), [p(1, 2), p(3, 4)]), _L199) ? creep 

는 이제 Pred를 가산 할 또 다른 솔루션을하자?

이 기법을 사용하려면 Pred를 복사하고 N과 P를 새로운 변수로 재귀 적으로 변경해야합니다. 매 반복마다 N과 P의 새 쌍을 "만들어야"합니다. copy_term/2 (http://www.swi-prolog.org/pldoc/doc_for?object=copy_term%2f2)를 확인하십시오.

관련 문제