2012-04-07 7 views
3

프로그램을 작성 중입니다. 제품 목록과 2 개의 주어진 수의 합계를 나타내는 숫자 목록을 작성해야합니다.Prolog - 재귀 목록 작성

지금은 목록에 목록을 추가하려는 횟수를 지정할 수있는 기능이 있습니다.이 기능은 나중에 전체 기능으로 확장됩니다.

가 여기에 내가 가진 무엇 : 그러나

s1(0, X). 
s1(Q, X) :- 
    N is Q - 1, 
    multiply(2, 3, Y), 
    A = Y , 
    add(2, 3, Z), 
    B = Z, 
    addToEnd([A], [B], X), 
    s1(N,X). 

multiply(A, B, C):- 
    C is A * B. 

add(A, B, C) :- 
    C is A + B. 

addToEnd([], L, L). 
addToEnd([H|T], L2, [H|L3]) :- 
    addToEnd(T, L2, L3). 

, 내가 예를 들어 s1(2,X)를 실행할 때, 나는 [6,5] 다음, 아무 것도 반환하지 얻을, 그냥 달려 있습니다. s1(0,X)을 실행하면 true이 표시되고 false;입니다.

아무도 도와 줄 수 있습니까? 내가 뭘 잘못하고 있는지 알 수가 없어. 작동해야한다고 생각해.

내가이 일을해야한다고 생각하는 방법을 명확히하기 위해 : 내가 s1(2,X). N = 1 전화, [6,5]s1(1,X). N=0 X([[6,5]])에 목록에 추가 [6,5]이있다, 그래서 s1(0,X). X = [[6,5],[6,5]]

답변

5

X ([[6,5],[6,5]])에 목록에 추가 여기에서 할 말이 많습니다. 가장 먼저 선언적 언어 에서처럼 변수는 실제로 값을 변경할 수 없습니다. 그게 무슨 뜻인지

은 예상대로 X = 1.X1를 통합하는 것입니다,하지만 당신은 쿼리 (X = 1, X = 2.)에 그 후 X = 2.를 추가하는 경우, 프롤로그는 false을 말할 것이다. 그 이유는 12으로 통합 할 수없고 X이 실제로 1이되어 X2으로 통합 할 수 없기 때문입니다.

비록 Haskell, Ocaml 등과는 다르지만 X = h(Y).과 같이 변수를 부분적으로 바인딩 할 수 있습니다. 그런 다음 이전에 언급 된 언어 (변수가 실제로는 값의 별칭 인 경우)에있을 수는 없지만 더 균일하게 X = h(a(Z)).을 통합 할 수 있습니다.

그는 왜 당신이 궁금해하는 모든 것을 말해 줍니까? 글쎄, 그것은 당신의 주된 문제입니다. 먼저 X[6, 5]에 바인딩 한 다음 다른 것으로 바인딩하려고합니다. 변수가 일단 그라운드되면 (즉, 내부에 자유 변수가 들어 있지 않은 경우) 변수의 값을 다시 변경할 수 없습니다.

여기에서 재귀는 아무 것도하지 않지만 결국 X 거짓을 증명합니다. 그러나 여기에서는 매번 동일한 인수 ([6], [5][6, 5])를 사용하여 addToEnd/3을 호출하는 것으로 끝납니다.

그렇다면 코드를 개선 할 수있는 방법을 살펴 보겠습니다.

첫째, 말은 : 다시 AB를 사용하지 않기 때문에

multiply(2, 3, Y), 
A = Y , 
add(2, 3, Z), 
B = Z, 
addToEnd([A], [B], X), 

는 정보의 손실없이

multiply(2, 3, Y), 
add(2, 3, Z), 
addToEnd([Y], [Z], X), 

을 기록 할 수 있습니다.

잠시 후 addToEnd/3을 잊어 버리고 원하는 것을 생각해 봅시다.

s1(0, Q)을 입력하면 실제로 Q을 무료로 유지 하시겠습니까? 그 순간에 당신이 말하는 것이기 때문입니다. 이 경우 Q[]에 묶는 것이 더 합리적입니다. 또한 곧 볼 수있는 것처럼 훌륭한 재귀 적 기본 사례를 만들 것입니다.

s1(0, []). 

프롤로그가 ( :- 전에 일부) 제 머리에 통일 않기 때문에

s1(0, Q) :- Q = []. 

말을 바로 가기입니다.

그렇다면 조금은 속이 겠지만 분명히 있어야합니다. s1(4, Q)에서 s1(5, Q)으로 갈 때 Q는 일부 미적분의 값을 하나 더 보유 할 것으로 예상됩니다. 제대로 따른다면, 우리가 직접 쓸 수

s1(N, [SomeCalculus|Q]) :- 
    PreviousN is N - 1, 
    X is 2 * 3, 
    Y is 2 + 3, 
    SomeCalculus = [X, Y], 
    s1(PreviousN, Q). 

또는 :

s1(N, [SomeCalculus|Q]) :- 
    PreviousN is N - 1, 
    s1(PreviousN, Q). 

을 이제 우리가 SomeCalculus에 값을 제공해야합니다 : 여기

, 우리는 다음과 같은 것을 주장 할 수 예 :

s1(0, []). 
s1(N, [[X, Y]|Q]) :- 
    PreviousN is N - 1, 
    X is 2 * 3, 
    Y is 2 + 3, 
    s1(PreviousN, Q). 

이제 이것을 테스트하면 ; 키를 눌렀을 때와 마찬가지로 프로그램이 루프 된 것처럼 보일 수 있습니다. Prolog는 두 번째 절이 0 에도 적용될 수 있다고 생각하기 때문입니다.

그럼 한 번 더 프로그램을 편집 할 수 :

s1(0, []). 
s1(N, [[X, Y]|Q]) :- 
    N > 0, 
    PreviousN is N - 1, 
    X is 2 * 3, 
    Y is 2 + 3, 
    s1(PreviousN, Q). 

이제 모든 것이 괜찮습니다.

나는이 재귀를 통해 적절한 조건을 구축하는 방법을 더 잘 이해하는 데 도움이 바랍니다. 변수에 대한 내용이 무엇이 잘못되었는지 많은 정보를 이미 알려 주었기 때문에 술어 addToEnd/3을 수정하는 데 많은 시간을 소비하지 않았습니다.

+0

대단히 감사드립니다. 정말 도움이됩니다. 사과에 대한 확신은 내 코드의 기본 오류입니다. 저는 프롤로그를 처음 접했고 C, Java 등에서 온 것입니다. 이것은 매우 다른 사고 방식입니다. – XavierNuquos

+0

@Mog : 아주 좋습니다! 당신은 정말로 교사로서 재능을 가지고 있습니다! – CapelliC

+0

@chac : thanks :) – m09