(is)/2
은 두 번째 인수에서 인스턴스화에 매우 민감합니다. 이는 완전히 관계형으로 사용할 수 없다는 것을 의미합니다. X is 1+1.
에게 물어볼 수도 있습니다. 2 is 1+1.
에게 물어볼 수도 있지만 물어볼 수는 없습니다 : 2 is X+1
.
따라서 (is)/2
과 같은 술어로 프로그래밍 할 때 술어와 함께 사용할 모드를 상상해보십시오. 이러한 고려 사항으로 인해 오류가 발생하기 쉽습니다 (특히 방금 시작한 경우). 하지만 걱정하지 마라. 더 능숙한 프로그래머는 여전히 그런 문제에 빠져 든다.
몇 가지 Prolog 시스템에는 깨끗한 대안이 있습니다. SICStus, YAP, SWI에는 정수 사이의 관계를 표현할 수있는 library(clpfd)
이 있습니다. 보통이 라이브러리는 제약 프로그래밍에 사용되지만 정수로 (is)/2
을 안전하고 깨끗한 대체물로 사용할 수도 있습니다. 더군다나,이 라이브러리는 종종 결과 코드가 (is)/2
과 비슷한 속도로 매우 효율적으로 컴파일됩니다. 그래서 지금 다시 프로그램
?- use_module(library(clpfd)).
true.
?- X #= 1+1.
X = 2.
?- 2 #= 1+1.
true.
?- 2 #= X+1.
X = 1.
, 당신은 간단하게 쓸 수 있습니다 : 필요에 따라
move2(X,Y,1):- edge(X,Y).
move2(X,Y,N0):- N0 #>= 1, N0 #= N1+1, edge(X,Z), move2(Z,Y,N1).
이제 모든 거리를 얻을.
그러나 더있다 ...
가
move2/3
이 실제로 종료 있는지 확인하려면, 시도 :
?- move2(A, B, N), false.
false.
이제 우리는 move2/3
항상 종료 확신 할 수 있습니다. 항상? 당신이 더 우위를 추가 한 가정 :
이
edge(f, f).
이제 위의 질의가 반복됩니다.그러나 여전히 당신은 당신의 프로그램을 당신의 이익을 위해 사용할 수 있습니다! 노드의 수를 결정 :
?- setof(C,A^B^(edge(A,B),member(C,[A,B])),Cs), length(Cs, N).
Cs = [a, b, c, d, e, f, g, h],
N = 8.
그래서 가장 긴 경로는 7 조치를 취할 것입니다!
이제하지만 지금은 값으로 N
을 제한함으로써, 쿼리를 다시 요청할 수 있습니다 같거나 내지 7 이하 :이 추가 제약 조건으로
?- 7 #>= N, move2(A,B, N), false.
false.
, 다시 종단 정의가! 루프가 없습니다.
NN은 N + 1입니다. N은 아직 인스턴스화되지 않았습니다. 재귀 호출 후 이동 (그리고 꼬리 재귀 최적화를 잃게 ...) – CapelliC
덕분에, 그보고 싶었어! –
@chac : * 인스턴스화 됨 * – false