1. 개요 ¶
1973년 프랑스의 컴퓨터 과학자 Alain Colmerauer와 논리학자 Phillipe Roussel이 개발한, 인공 지능 분야에서 많이 쓰이는 논리학을 기초로 한 고급 프로그램 작성 언어. 단어(symbol)와 그들 사이에 있는 관계를 이용하여 문제를 해결한다. 단어로 표현되는 사실(fact)과 규칙(rule)으로 프로그램을 표현하며, 논리학에서의 first-order logic의 규칙을 그대로 따르고 있다. 주로 숫자 계산보다는 인공 지능 분야에서의 논리적인 추론이나 패턴 매칭, 리스트 처리 등에 적합하다.
http://wkddngur7800.mytripod.co.kr/_temp_16.htm 이 페이지의 표현을 다소 다듬었습니다.
2. 특징 ¶
PrologLanguage 는 declarative language (iterative language와 대비하여) 혹은 logical language (functional language와 대비하여) 로 분류된다.
- PrologLanguage의 syntax는 first-order logic (위 사이트에서 1차 서술 논리라고 한 것이 아마 이것을 의미하는듯?) 의 문법을 조금 더 타이핑하기 쉽고 심볼릭하게 정제한 형태의 문법을 사용한다. 가독성은 조금 떨어지지만. 이 logic algebra의 domain은 거의 항상 symbol(문자열)이고 숫자 연산을 지원한다.
- PrologLanguage의 semantics는 몇 개의 명제를 선언 하는 의미를 갖게 된다.
- example : (가장 흔한 버전)
father(john, mary). father(bob, john). grandfa(A, B) :- father(A, C), father(C, B). ?- grandfa(bob, mary). yes. ?- grandfa(mary, john). no. ?- grandfa(A, mary). A = bob? ; no.
- PrologLanguage는 아주 지능적인 back tracking과 unification을 통해 이같은 기능을 구현한다. 주어진 query (앞의 예에서 ?- 뒤에 쓴 것들) 를 만족시키기 위해 필요한 명제들을 차례로 평가하면서, 각 변수들은 최대한 늦게 평가함으로써 각 변수들이 항상 필요한만큼만의 값을 가지도록 한다. 만약 하나의 명제가 실패한다면, 강력한 back tracking 기능으로 그 명제를 참으로 만들 수 있는 다른 명제들을 순차적으로 평가한다.
이와 같은 특징으로 인해 종종 변수의 값을 평가하기 위해 무한 루프에 빠지는 일을 방지하기 위해, back tracking을 막기 위한 cut 이라는 언어 스펙을 지원한다.
- PrologLanguage는 symbol 처리를 위한 강력한 도구들을 제공한다. 문자들은 어떤 식으로든 구조화될 수 있으며, 각 symbol들은 개개의 문자를 list로 떼어내거나 구조 자체가 변수와 unification 될 수 있는 기능을 지원한다. list는 . (period) 라는 특수한 symbol을 통해 구현된다.
ex :[1,2,3] = .(1,.(2,.(3,[])))
- 타입 체크가 아주 약하다. 모든 값들은 functional structure (단일 symbol은 0-ary function이다.)이거나 숫자이기 때문에, 실제 domain에 따른 타입 체크를 지원하지 않는다. 그러나 무한대에 가까운 fuctional structure 지원으로, 타입 체크는 얼마든지 할 수 있다.
3. 활용 분야 ¶
- 강력한 symbol 처리 능력으로 인해, 자연어 처리(NaturalLanguageProcessing, NLP) 분야에서 가장 활발하게 이용되고 있다. (자연어 검색 엔진 등)
- symbolic AI 분야에서 많이 사용된다.
- 연구용이 아닌 실제 개발에서 사용하기 위해서는 CppLanguage이나 JavaLanguage에 embed하는 방식으로 사용하면 효과적일 것 같다.
4. 예시 프로그램 ¶
- list 합치기. 이것은 한 list의 뒤에 다른 list를 잇는 concat 연산의 정의를 선언한 것이다.
concat([],A,A). // 빈 list [] 와 A를 합치면 A이다. concat([H|T],A,[H|R]) :- concat(T,A,R). // T와 A를 합쳐서 R이 된다면, [H|T]와 A를 합쳐서 [H|R] 이 된다.
PrologLanguage에서 별도의 명시 없이 사용한 단어는 소문자로 시작하면 symbol 또는 predicate, 대문자로 시작하면 variable이 된다. first-order logic 이므로 predicate 위치에는 variable이 올 수 없다. (즉 variable은 symbol들로 이루어진 functional structure만을 가질 수 있다.)
위 프로그램에concat([a,b],[c,d],R0)
. 이라고 query를 주면, 다음과 같은 순서대로 연산이 일어난다.
- 첫번째 선언과 query를 unify 해본다.
[a,b]
는[]
와 unify 될 수 없으므로 실패한다.
- 두번째 선언과 query를 unify 해본다.
H=a, T=[b], A=[c,d], R0=[a|R1]
이고concat([b],[c,d],R1)
이 만족해야 한다.
concat([b],[c,d],R1)
과 첫번째 선언을 unify할 수 없으므로 다시 두번째 선언과 unify 한다.H=b, T=[], A=[c,d], R1=[b|R2]
이고concat([],[c,d],R2)
가 만족해야 한다.
- 첫번째 선언에 의해
R2=[c,d]
이다.R1=[b,c,d]
이고R0=[a,b,c,d]
이다. 원래 query에서 모든 변수가 instantiate 되었으므로 query의 결과를 낸다.R0=[a,b,c,d] ?
- 여기에서 ; 을 입력하여 더 원하는 값이 있는지 찾게 하면, PrologLanguage는 마지막으로 성공한 unification을 실패로 간주하고 다른 가능성이 있는지 찾는다. 이 경우
concat([],[c,d],R2)
를 첫번째 선언과 unify한 것을 실패로 간주하고 두 번째 선언과 unification을 시도한다.[H|T]
와[]
는 서로 unify 될 수 없으므로 실패. 그 이전 단계들도 이미 모든 concat/3 (3개의 인자를 받는 concat predicate)과 unification을 시도해보았기 때문에, 더 이상의 가능성이 없다고 보고 no. 를 답으로 낸다. (즉, query 문장이 거짓이라는 의미이다.)
다음과 같은 query 도 가능하다. - 첫번째 선언과 query를 unify 해본다.
?- concat(A,[c,d],[a,b,c,d]). A = [a,b]?
모든 프로그램에서 이러한 역 query 가 가능한 것은 아니지만 교수님의 표현을 빌려 이런 것이 prolog의 beauty 이다 -_-;
이 프로그램은 time complexity 가 O(n) (n은 앞쪽 list의 길이) 라는 단점이 있다. 이것을 constant time 에 해내기 위한 몇 가지 꽁수가 있다. ;
not(A) :- A, !, fail. not(_).! 은 cut이라는 스펙으로, 강제로 backtracking을 중단시킬 때 사용한다.
위 선언을 아까 저~~위의 example 과 함께 선언한 뒤 not(father(bob, mary)). 를 query로 주면 다음과 같은 순서대로 연산이 일어난다.
- 첫번째 선언과 query를 unify 해본다. A=grandfa(bob, mary)이다.
- A는 grandfa(bob,mary)이고 위에서 봤듯 이 명제는 참이다.
- !은 cut으로, 명제 자체는 참값을 가진다.
- fail은 무조건 실패한다. 실패했으므로 앞의 명제를 다르게 unify해서 성공할 가능성이 있는지 backtracking을 시도한다.
- 앞의 명제 !은 두번째로 평가될 때에는 스스로 실패할 뿐 아니라 더 이상의 backtracking도 모두 금지한다. 즉 이 query는 무조건 실패한다. (명제의 참값이 거짓이 되며, 인터프리터는 no.라고 표시해준다.)
- A는 grandfa(bob,mary)이고 위에서 봤듯 이 명제는 참이다.
- 첫번째 선언과 query를 unify 해본다. A=grandfa(mary,john).
- A는 grandfa(mary,john)이고 이 명제는 거짓이므로 첫 번째 선언은 실패한다.
- A는 grandfa(mary,john)이고 이 명제는 거짓이므로 첫 번째 선언은 실패한다.
- 두번째 선언과 query를 unify 해본다. _는 anonymous variable로, 모든 structure와 unify될 수 있다. _=grandfa(mary, john). 이 명제에는 필요조건명제가 없으므로 성공한다. 즉 이 query는 참이다.
5. 인터프리터 및 개발도구 ¶
- SICSTUS Prolog prolog의 표준을 선도하는 대표주자(?). 단지 위에서 예시한 not이나 concat등을 모듈로 제공하지 않아서 일일이 구현해서 써야 한다는 불편함이 있다.
- SWIProlog 오픈소스와 Lesser GNU Public License를 채택한 인터프리터. 리눅스와 윈도우, Mac 등의 플랫폼에 포팅되어있다는 장점이 있다.
- swiprolog-c++ CppLanguage 와 prolog 를 함께 사용할 수 있게 만든 환경. 안써봐서 뭔지는 모르겠다 @_@
- JLog JavaLanguage안에서 사용할 수 있는 PrologLanguage인터프리터. Java Applet으로 된 예제를 제공한다.
- GNU Prolog GNU Prolog is a free Prolog compiler with constraint solving over finite domains developed by Daniel Diaz.