2013-11-21 1 views
3

내가 프롤로그 프로그램에서 초보자 해요 필요로하고 내가 겸손을 희망 제가 프롤로그에서 합계를 계산하는 문제에 직면하고있어 혼란합계는 약간의 설명

를 전달하는 데 도움이 나는 대답을 가지고 있지만 그것은 분명하지 않습니다. 대답은 :

list_sum([], 0). 
list_sum([Head | Tail], Total) :- 
    list_sum(Tail, Sum1), 
    Total = Head + Sum1. 

가 무엇인지 이해하지 않은 것은 Sum1 프로그램이 단계

에서 작동하는 방법을 먼저 첫 번째 조건 list_sum([], 0).을 확인 무슨이다 조건이 충족되지 않은 상태 것이다 목록을 HeadTail의 두 부분으로 나눕니다.


조금 초보자라도 받아 들여서 혼란 스러울 때가 있기를 바랍니다.
너희들 고마워 너희들

답변

4

이것은 고전적인 재귀 접근법이다 - 당신은 Prolog를 이해하는데 익숙해 져야한다.

규칙에는 두 개의 절이 있습니다. 하나는 빈 목록을위한 것이고 다른 하나는 비어 있지 않은 항목입니다. 빈 목록 절은 빈 목록의 요소 합이 0이라고 말합니다 (이는 매우 합리적입니다). 이것은 "재귀의 기본 경우"라고합니다. 모든 종결 재귀 규칙에는 기본 사례가 있어야합니다.

두 번째 절은 좀 더 복잡합니다. "비어 있지 않은 목록의 요소 합계를 계산하고 처음 요소를 잘라내어 결과가 더 짧은 목록의 요소 합계를 계산하려면 Sum1을 호출하십시오. 이제 Total을 추가하여 계산하십시오 첫 번째 요소의 값은 Sum1의 값으로

두 번째 절은 빈 목록에 도달 할 때까지 일련의 짧은 목록으로 재귀 적으로 분해합니다.이 시점에서 첫 번째 절은 단계 .

list_sum([12, 34, 56], X) 
    list_sum([34, 56], <unknown-1>) 
     list_sum([56], <unknown-2>) 
      list_sum([], 0)   ---> succeeds with Total bound to 0 
     <unknown-2> becomes 0 + 56 ---> succeeds with Total bound to 56 
    <unknown-1> becomes 0 + 56 + 34 ---> succeeds with Total bound to 90 
X becomes 0 + 56 + 34 + 12   ---> succeeds with X bound to 102 
: 빈리스트

이 예제를 고려

이것은 재귀 체인의 각 호출 수준이 Sum1에 대한 고유 한 변수를 갖기 때문에 효과가 있습니다. 이 값들은 무제한으로 시작하지만 재귀 적 호출 체인이 "바닥으로 떨어지면"Sum1은 각 이전 수준에서 계산 된 값을 가져 오기 시작합니다. 결국, 호출 체인은 최상위 레벨에 도달하여 호출자가 전달한 변수에 최종 결과를 바인딩합니다.

+0

정말 고맙습니다. 고맙습니다. 신의 축복이 있습니다. 처음에는 그것을 이해하기가 너무 어려웠습니다. 하지만 당신은 모두 나를 위해 간단하게 명확하게 만들었습니다. – user3018890

+0

"102로 돌아 오는"등의 좋은 설명은 약간의 오해의 소지가 있습니다. 특히 절차 적 사고를하는 데 익숙한 사람에게는 더욱 그렇습니다. 프롤로그 절은 값을 반환하지 않습니다. 그들은 전혀 "돌아 오지 않는다". "X가 102로 묶여서 성공"하는 것과 같은 말을하는 것이 더 정확할 것입니다. –

+0

@TedHopp 나는 그것에 대해서도 생각했습니다. 반환은 약간 오도하는 것입니다. "with"를 추가하여 값이 절차 적 의미에서 "반환"되지 않는다는 것을 암시합니다. 나는 당신의 말씨가 내 것이 낫다는 것을, 그러나, - 훌륭한 코멘트를 주셔서 감사합니다! – dasblinkenlight

5

처음에는 프로그램에 약간의 오류가 있습니다. 라인 Total = Head + SumTotal이 두 개의 인수가있는 + 구조임을 의미합니다. 산술 평가를 의미하는 = 대신 아마도 is을 의미합니다. 하지만 가장 좋은 방법은 대신 #=을 사용하는 것입니다.

질문에서 은 프로그램이 수행 할 내용을 묻습니다.. 이는 명령 지향적 인 (명령형) 언어에서 상당히 합리적인 질문입니다. 프로그램에서 얻을 수있는 유일한 의미는 단계별 조치이기 때문입니다. 그러나 여기 Prolog에서는 상황이 조금 다릅니다. 그 단계별 사고를 적용하려고 시도 할 수는 있지만 조만간 Prolog는 하나의 제어 흐름이 없지만 동시에 두 개 (AND 및 OR) 호출이 필요하기 때문에 상황이 극도로 복잡해질 수 있음을 알게 될 것입니다. 제어). 심지어 "데이터 구조"도 다릅니다 ...

그러나 명령형 언어로는 상응하지 않는 Prolog 프로그램을 읽을 수있는 방법이 있습니다. 프로그램을 인수 간의 관계로 이해할 수 있습니다. 이러한 방식으로, 당신은 절차 적 측면에서 관계가 어떻게 보이는지에 집중할 수 있습니다. 어쨌든 묘사 된 관계가 틀린 경우에, 프로그램이 이것을 어떻게하는지 질문하는 아무 점도 없다.

그래서 제가 프로그램을 바꿔 보자 먼저 첫 번째 조건의 list_sum을 확인합니다

:- use_module(library(clpfd)). 
list_sum([], 0). 
list_sum([E|Es], S) :- 
    S #= E+T, 
    list_sum(Es, T). 

([], 0). 조건이 충족되지 않으면 목록을 H와 T의 두 부분으로 나눕니다.

귀하의 질문은 단일 제어 흐름 ("그와 같은 일반적인 구성입니다.")이라는 것을 의미합니다. 그러나 그것은 다르게 작동 할 수도 있습니다. 쿼리를 생각해

?- list_sum(Xs,0). 
Xs = [] ; 
Xs = [0] ; 
Xs = [_G1710, _G1713], 
_G1710+_G1713#=0 ... 

가 여기에 우리가 에게 무엇을 나열하는 것은 누구의 합이 0이다 존재한다. 이제 "동안"은 더 이상 의미가 없습니다.

답변은 다음과 같습니다. 빈 목록. 0와의 목록; 요소의 합이 0 인 2 요소 목록. 등 ...

이러한 프로그램을 이해하는 가장 좋은 방법은 지금과 같은 관계로 읽을 것입니다 :

list_sum([], 0 : 빈 목록은 합계 0 있습니다.

규칙이 이제 오른쪽에서 왼쪽 인 :- 화살표의 방향으로 가장 읽

  • list_sum(Es, T). * Es 제공되는 합 T와 목록 ...

  • 이다
  • S #= E+T ... S은 ... E 플러스 T입니다

  • :- ... 그럼 우리는 결론을 내릴 수 있습니다 ...

  • list_sum([E|Es], S) : S은 목록의 합이 [E|Es]입니다.

이런 식으로 절차상의 세부 사항을 너무 많이 언급하지 않고도 이러한 것들을 이해할 수 있습니다. 이해가 끝나는 것처럼 더 많은 것이 있습니다 을 참조하십시오.

+0

그래, 나는 그걸 알아 차렸다. 설명 – user3018890

+1

+1을 주셔서 감사합니다.이 스타일을 사용하여 술어를 읽고 정수 연산에 유한 도메인 제약 조건을 사용하는 것이 좋습니다. – mat