Tải bản đầy đủ (.pdf) (23 trang)

ngôn ngữ Prolog và ứng dụng lập trình Prolog

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (809.34 KB, 23 trang )

Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 1

LỜI NÓI ĐẦU

Prolog - xuất phát từ cụm từ tiếng Pháp Programmation en logique - là "lập trình theo lô gích".
Prolog xuất hiện từ năm 1972, do Alain Colmerauer và Robert Kowalski thiết kế. Mục tiêu của
Prolog là giúp người dùng mô tả lại bài toán bằng ngôn ngữ của logic. Dựa trên đó, máy tính sẽ tiến
hành suy diễn tự động dựa vào những cơ chế suy diễn có sẵn (hợp nhất, quay lui và tìm kiếm theo
chiều sâu) để tìm câu trả lời cho người dùng.
Prolog được sử dụng nhiều trong các ứng dụng của trí tuệ nhân tạo và ngôn ngữ học trong khoa học
máy tính, đặc biệt là trong ngành xử lý ngôn ngữ tự nhiên. Cú pháp và ngữ nghĩa của Prolog đơn giản
và sáng sủa. Nó được người Nhật coi là một trong những nền tảng để xây dựng máy tính thế hệ thứ
năm, mà ở đó thay vì phải mô tả cách giải quyết một bài toán trên máy tính, con người chỉ cần mô tả
bài toán và máy tính sẽ hỗ trợ họ nốt phần còn lại.
Trong bài thu hoạch môn học Biểu diễn tri thức và suy luận này, em xin trình bày khái quát về
ngôn ngữ Prolog và ứng dụng lập trình Prolog cho 3 bài toán: tháp Hà Nội, tính giai thừa, và lập gia
hệ.

Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 2
I. Ngôn ngữ Prolog
1. Giới thiệu
Prolog là một ngôn ngữ lập trình. Tên gọi Prolog được xuất phát từ cụm từ tiếng Pháp
Programmation en logique, nghĩa là "lập trình theo lô-gích". Xuất hiện từ năm 1972 (do Alain
Colmerauer và Robert Kowalski thiết kế).
Mục tiêu của Prolog là giúp người dùng mô tả lại bài toán trên ngôn ngữ của logic. Dựa trên đó,
máy tính sẽ tiến hành suy diễn tự động dựa vào những cơ chế suy diễn có sẵn (hợp nhất, quay lui
và tìm kiếm theo chiều sâu) để tìm câu trả lời cho người dùng.
Prolog được sử dụng nhiều trong các ứng dụng của trí tuệ nhân tạo và ngôn ngữ học trong khoa
học máy tính (đặc biệt là trong ngành xử lý ngôn ngữ tự nhiên vì đây là mục tiêu thiết kế ban đầu


của nó).
Cú pháp và ngữ nghĩa của Prolog đơn giản và sáng sủa. Nó được người Nhật coi là một trong
những nền tảng để xây dựng máy tính thế hệ thứ năm: thay vì phải mô tả cách giải quyết một bài
toán trên máy tính, con người chỉ cần mô tả bài toán và máy tính sẽ hỗ trợ họ phần còn lại.
Nguyên lý của lập trình theo lô-gích dựa trên các mệnh đề Horn. Một mệnh đề Horn biểu diễn
một sự kiện nào đó là đúng hoặc không đúng, xảy ra hay không xảy ra.
Ví dụ:
 Thạch là một học viên cao học.
 Nếu Thạch học tốt thì sẽ được làm luận văn.
 Nếu A là cha mẹ của B và B là cha mẹ của C thì A là ông bà của C.
2. Các thuật ngữ:
Một chương trình Prolog là một cơ sở dữ liệu gồm các mệnh đề (clause). Mỗi mệnh đề được xây
dựng từ các vị từ. Một vị từ có thể có một hoặc nhiều nguyên tử logic (logic atom). Mỗi logic
atom biểu diễn quan hệ giữa các hạng (term). Term có thể sơ cấp (elementary term) như các hằng,
các biến và phức hợp (compound term)
Các term phức hợp biểu diễn các đối tượng phức tạp của bài toán đang xét. Term phức hợp là một
hàm tử (functor) có đối số (argument), các functor này có dạng:
 Tên_functor(Đối_1, Đối_2,…, Đối_n)
Trong đó:
 Tên_functor là một chuỗi gồm các chữ cái và chữ số và được bắt đầu bằng một chữ cái
thường.
 Các đối có thể là biến, term sơ cấp hoặc phức hợp.
Mệnh đề có thể là một sự kiện, một luật hay một câu hỏi. Prolog quy ước sau mỗi mệnh đề cần có
một dấu chấm để kết thúc.
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 3
3. Các kiểu dữ liệu:
Prolog có hai dạng kiểu dữ liệu: sơ cấp và có cấu trúc.
 Kiểu dữ liệu sơ cấp: gồm một số kiểu dữ liệu được định nghĩa sẵn trong Prolog như:
 char: kiểu ký tự, khi sử dụng đặt trong cặp dấu nháy đơn.Ví dụ: ‘a’, ‘b’, …

 string: kiểu chuỗi, khi sử dụng đặt trong cặp dấu nháy đôi. Ví dụ: “hoc vien cao hoc”
 integer: kiểu số nguyên.
 unsigned: kiểu số nguyên dương không dấu.
 real: kiểu số thực.
 Kiểu dữ liệu có cấu trúc: do người dùng tự định nghĩa dựa trên các kiểu sơ cấp đã có sẵn.
Có một số trình biên dịch ngôn ngữ Prolog không yêu cầu người dùng phải khai báo kiểu dữ liệu
được dùng (ví dụ như SWI-Prolog). Tuy nhiên, việc khai báo này là cần thiết đối với các hàm hay
vị từ trong Visual Prolog.
4. Chú thích
Tương tự như các ngôn ngữ khác, trong một chương trình Prolog, người dùng có thể thêm vào
các chú thích (comment). Khi muốn chú thích cho một dòng, có thể sử dụng dấu % và sử dụng
cặp dấu /* và */ khi chú thích nhiều dòng.
Ví dụ:
 % đây là một dòng chú thích
 /* đây cũng là một dòng chú thích */
 /* đây là chú thích
trên
nhiều dòng */
5. Biến:
Người dùng có thể sử dụng các biến trong Prolog với quy ước như sau: Tên biến được quy ước là
một chuỗi gồm chữ cái và chữ số và luôn bắt đầu bằng một chữ cái hoa hoặc dấu gạch dưới _.
Ví dụ:
 Tên các biến sau là không hợp lệ: uoc_so, 2n, 345, …
 Tên các biến sau là hợp lệ: X, Ten, _, _Phai, Uoc_so, …
Trong Prolog, có một biến đặc biệt không cần chỉ định kiểu khi sử dụng, đó là dấu gạch dưới _.
Dấu gạch dưới được xem như một biến, sử dụng cho một vị từ nào đó có một đối mà với bất kỳ
giá trị nào của đối này cũng nhận được một giá trị duy nhất.
6. Phép toán số học:
Prolog chủ yếu hỗ trợ xử lý các ký hiệu. Tuy nhiên, nó cũng hỗ trợ một số phép toán hai ngôi
chuẩn như sau:

Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 4
Phép toán 2 ngôi
Ý nghĩa
+
Cộng 2 số
-
Trừ 2 số
*
Nhân 2 số
/
Chia hai số
Mod
Chia lấy phần dư
Div
Chia lấy phần nguyên
Phép so sánh 2 ngôi
Ý nghĩa
>
Lớn hơn
>=
Lớn hơn hoặc bằng
<
Nhỏ hơn
<=
Nhỏ hơn hoặc bằng
<> Hoặc ><
Khác
:=
Bằng

Với toán tử logic, Prolog sử dụng dấu phẩy , thay cho toán tử and (và) và dấu chấm phẩy ; thay
cho or (hoặc).
7. Sự kiện và luật:
Sự kiện: là một vị từ diễn tả một sự thật.
Ví dụ:
 “2 là một số nguyên tố” là một sự kiện vì nó diễn tả sự thật.
Ta có thể diễn đạt dưới một vị từ trong Prolog như sau: nguyen_to(2).
Ví dụ: Xét cây phả hệ như sau:

Cây phả hệ gia đình
 Trong đó, các nút tròn đại diện cho 1 người, các mũi tên biểu diễn cho mối quan hệ “là
cha mẹ của”.

an

bình

hạnh

phúc

phú

quý

tài
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 5
 Sự kiện “an là cha mẹ của hạnh” sẽ được diễn đạt bằng một vị từ như sau:
 cha_me(“an”, “hanh”).

 Vị từ cha_me có 2 đối là “an” và “hanh”.
Dưới đây là 6 vị từ diễn đạt cho cây phả hệ trên:
 cha_me(“an”, “hanh”).
 cha_me(“binh”, “hanh”).
 cha_me(“binh”, “phuc”).
 cha_me(“hanh”, “phu”).
 cha_me(“hanh”, “quy”).
 cha_me(“quy”, “tai”).
Luật: là một vị từ diễn tả quy luật suy diễn được công nhận đúng. Luật được trình bày dưới dạng
một mệnh đề. Trong Prolog, để định nghĩa cho một luật, ta sử dụng cặp ký tự :-
Ví dụ:
 Ta định nghĩa thêm vị từ con_cai(X, Y) với 2 đối số là X và Y, mang ý nghĩa “X là con
cái của Y”.
 Ta sẽ có luật như sau: con_cai(X,Y):-cha_me(Y,X), được hiểu là “X là con cái của Y nếu
Y là cha mẹ của X”.
Ví dụ:
 Để diễn tả luật: “ai là người đều phải chết”, ta viết như sau: chet(X):-nguoi(X).
Ví dụ:
 Xét định nghĩa sau: “N là một số nguyên tố nếu N>0, M là số nguyên tố nào đó, M<N và
N không chia hết cho M”.
 Khi biểu diễn bằng Prolog, ta có thể viết như sau: nguyen_to(N):-N>0, nguyen_to(M),
M<N, N mod M <> 0.
Phân biệt sự kiện và luật:
 Sự kiện là một điều luôn đúng và không có ràng buộc.
 Luật thì phải phụ thuộc vào các biến hay thuộc tính và khi thoả mãn điều kiện nào đó thì
là đúng.
 Một luật thường gồm hai phần:
o Phần bên trái dấu :- được gọi là kết luận hay phần đầu (head) của luật.
o Phần bên phải dấu :- được gọi là điều kiện hay phần thân (body) của luật.
 Nếu điều kiện đúng thì phần kết luận cũng đúng. Đó là hậu quả logic của phép suy luận

(inference).
8. Chương trình Prolog:
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 6
Một chương trình Prolog thường gồm 4 phần cơ bản như sau: domains, predicates, clauses và
goal.
domains:
 Đây là phần định nghĩa kiểu dữ liệu mới dựa vào các kiểu dữ liệu đã biết.
 Các kiểu dữ liệu được định nghĩa ở đây sẽ được sử dụng cho các đối số trong các vị từ.
 Nếu các vị từ sử dụng đối số có kiểu cơ bản thì có thể không cần phải định nghĩa lại các
kiểu đó. Tuy nhiên, ta nên định nghĩa lại các kiểu cơ bản để chương trình sáng sủa.
 Cú pháp:
<danh sách kiểu mới> = <kiểu đã biết>
hoặc
<danh sách kiểu mới> = <danh sách kiểu đã biết>
Trong đó, <kiểu đã biết> có thể là kiểu cơ bản (như số nguyên, số thực, …) hoặc các kiểu
đã được định nghĩa trước. Các kiểu mới phân cách nhau bởi dấu phẩy, còn các kiểu đã biết
phân cách nhau bởi dấu chấm phẩy ;
Ví dụ:
domains
ten, tac_gia, nha_xb, dia_chi = string.
nam, thang, so_luong = integer.
dien_tich = real.
nam_xb = nxb(thang, nam).
do_vat = sach(tac_gia, ten, nha_xb, nam_xb); xe(ten, so_luong); nha(dia_chi, dien_tich).
Trong ví dụ trên, ta đã định nghĩa các kiểu mới ten, tac_gia, nha_xb, dia_chi dựa vào cùng một
kiểu cơ bản đã biết là string.
Đồng thời, ta định nghĩa các kiểu mới nam, thang, so_luong dựa vào cùng một kiểu đã biết là
integer.
Kiểu mới dien_tich dựa vào kiểu đã biết là real.

Kiểu mới nam_xb dựa vào kiểu nxb được xây dựng từ các kiểu đã biết là thang, nam
Kiểu do_vat dựa vào các kiểu sach, xe, nha mà các kiểu này lại dựa vào các kiểu đã biết.
predicates:
 Đây là phần bắt buộc phải có. Trong phần này, cần phải khai báo đầy đủ các vị từ sử dụng
trong phần clauses, ngoại trừ các vị từ mà trình biên dịch Prolog đã xây dựng sẵn.
 Cú pháp:
<Tên vị từ> (<danh sách các kiểu>)
Trong đó, <danh sách các kiểu> là các kiểu cơ bản hoặc là các kiểu đã được định nghĩa
trong phần domains và được viết phân cách nhau bởi dấu phẩy.
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 7
Ví dụ:
predicates
so_huu (ten, do_vat).
nguyen_to(integer).
nguoi(ten).
cha_me(ten, ten).
Trong ví dụ trên ta khai báo 4 vị từ. Trong đó:
 Vị từ so_huu (ten, do_vat) để chỉ một người có tên là ten sẽ sở hữu môt do_vat nào đó.
 Vị từ nguyen_to(integer) để xét xem một số nguyên nào đó có phải là số nguyên tố hay
không.
 Vị từ nguoi(ten) để xét xem một cái tên ten nào đó có là người không.
 Vị từ cha_me(ten, ten) xét xem một người có tên là ten (đối thứ nhất) có là cha mẹ của
người có tên là ten (đối thứ hai) hay không.
clauses:
 Đây là phần bắt buộc phải có, dùng để mô tả các sự kiện và các luật, sử dụng các vị từ đã
khai báo trong phần predicates.
 Cú pháp:
<Tên vị từ>(<danh sách các tham số>) <kí hiệu>
<Tên vị từ 1>(<danh sách các tham số 1>) <kí hiệu>


<Tên vị từ N>(<danh sách các tham số N>) <kí hiệu>
Trong đó, Tên vị từ phải được khai báo trong phần predicates.
 Các tham số có thể là các hằng hoặc biến có kiểu tương thích với các kiểu tương ứng đã
được khai báo trong các vị từ ở trong phần predicates và được viết cách nhau bởi dấu
phẩy.
 Các kí hiệu bao gồm:
:- điều kiện “nếu”.
, điều kiện “và”.
; điều kiện “hoặc”.
. kết thúc vị từ.
Ví dụ:
clauses
 nguyen_to(2).
 nguyen_to(N):-N>0, nguyen_to(M), M<N, N mod M <>0.
 so_huu(“Tran Thi HongYen”, sach(“Do Van Nhon”, “Giao Trinh Toan Roi Rac”, “Khoa
Hoc Co Ban”, nxb(9,2006))).
 nguoi(“Socrates”).
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 8
 chet(X):-nguoi(X).
Lưu ý: Nếu trong các tham số của một vị từ có biến thì biến này phải xuất hiện ít nhất 2 lần trong
vị từ đó hoặc trong các vị từ dùng để suy diễn ra vị từ đó. Nếu chỉ xuất hiện một lần thì bắt buộc
phải dùng biến tự do.
Ví dụ:
 Để diễn tả sự kiện: Tổ hợp chập 0 của N bất kỳ bằng 1, ta không thể viết To_hop(N,0,1)
vì biến N chỉ xuất hiện đúng một lần trong vị từ này, mà phải viết là To_hop(_,0,1) .
goal:
 Ở phần này, người dùng sẽ đưa ra các mục tiêu cần tìm kết quả, thực chất là các câu hỏi
mà người dùng muốn Prolog trả lời dựa vào các sự kiện và luật đã được khai báo và định

nghĩa ở trên.
 Cú pháp phần goal giống như cú pháp phần clauses, nghĩa là đưa vào một hoặc một số các
vị từ. Nếu tất cả các tham số của vị từ là hằng thì kết quả nhận được là true (hoặc Yes -
đúng) hoặc false (hoặc No - sai). Nếu trong các tham số của vị từ có biến thì kết quả trả về
sẽ là các giá trị của biến.
Ví dụ:
 Muốn biết 4 có phải là số nguyên tố không thì trong phần goal sẽ nhập vị từ sau:
nguyen_to(4), và kết quả nhận được sẽ là false.
 Nếu phần goal được nhập là nguyen_to(X), thì câu trả lời là X=2
 Ngoài các phần chủ yếu nói trên, có thể đưa vào các phần liên quan đến khai báo hằng,
các tập tin liên quan hoặc chỉ thị dịch.
Ví dụ:
Để khai báo hằng số Pi, ta viết:
constants
Pi = 3.141592653
Lưu ý: tùy theo trình biên dịch, thể hiện phần goal sẽ khác nhau. Một số trình biên dịch cho người
dùng nhập phần goal sau dấu nhắc ?- (như B-Prolog hay SWI-Prolog). Tuy nhiên, cũng có trình
biên dịch như Turbo-Prolog hay Visual Prolog thì các mục tiêu viết sau từ khóa goal.
9. Phép hợp nhất
Công việc quan trọng nhất của Prolog trong việc tìm câu trả lời là thực hiện việc hợp nhất. Phép
hợp nhất sẽ được biểu diễn bởi dấu =. Nó có hai thành phần: vế trái và vế phải. Phép hợp nhất sẽ
trả về kết quả true (thành công) hoặc false (thất bại).
Có các trường hợp hợp nhất sau:
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 9
a. Cả hai vế đều là hằng hoặc biểu thức chứa toàn hằng: nếu giá trị của hai vế là bằng
nhau thì phép hợp nhất thành công (kết quả là true), ngược lại phép hợp nhất sẽ thất bại
(kết quả là false).
Ví dụ 15:
 9 = 9  true

 7 = 9  false
 2 = 1 +1  false
 2+1 = 1+2  true.
 “xyz” = “xyz”  true
 “xyzt” = “xyz”  false
b. Một trong hai vế là hằng hoặc trong biểu thức chứa toàn hằng, vế kia là biến hoặc
biểu thức có chứa biến.
Nếu tất cả các biến đều có giá trị (các biến ở tình trạng bound) thì quay về trường hợp a.
 9 = X  false nếu X đã có giá trị là 8
 9 = X +1  true nếu X đã có giá trị là 8
 Y = “Socrates”  true nếu Y đã có giá trị là “Socrates”
Nếu có biến chưa có giá trị (biến ở tình trạng unbound), Prolog sẽ gán giá trị cho biến sao
cho hai vế có giá trị như nhau và trả về kết quả là true. Nếu không tìm giá trị như vậy,
phép hợp nhất sẽ cho kết quả là false.
 9 = X  true nếu X chưa có giá trị, sau phép hợp nhất này, X sẽ có giá trị là 9
 -1 = X*X  false vì không thể tìm cho X giá trị nào làm cho giá trị hai vế là như
nhau.
c. Cả hai vế đều là biến hoặc các biểu thức có chứa biến:
Nếu tất cả các biến đều có chứa giá trị thì quay về trường hợp a.
 X = Y  true nếu cả X và Y đều đã có giá trị và những giá trị này bằng nhau.
 X - 1 = Y  false nếu X và Y đều đã có giá trị và X nhỏ hơn Y.
Nếu tất cả các biến của một vế đều đã có giá trị, quay về về trường hợp c
 X = Y  true nếu X chưa có giá trị và Y đã có giá trị, sau phép hợp nhất, X sẽ
nhận giá trị của Y
 X - 1 = Y  true nếu X chưa có giá trị, Y đã có giá trị. Sau phép hợp nhất, X sẽ có
giá trị bằng Y +1
Cả hai vế đều còn chứa biến ở tình trạng unbound thì hợp nhất vẫn thành công và mỗi khi
một biến nào đó trong vế phải hoặc vế trái có giá trị thì biến còn lại cũng sẽ được ràng
buộc với giá trị đó.
 X = Y  true nếu cả X và Y đều chưa gán giá trị.

 X - 1 = Y  true nếu cả X và Y đều chưa gán giá trị.
10. Cơ chế tìm câu trả lời của Prolog:
Khi nhận được một câu hỏi ở phần goal thì Prolog sẽ thực hiện công việc so khớp (match), tức là
tìm mệnh đề đầu tiên đề cập đến khái niệm mà nó nhận được. Cụ thể là Prolog sẽ dùng phép hợp
nhất đã trình bày ở trên trong quá trình so khớp cấu trúc dữ liệu một mục tiêu với một mệnh đề.
Giả sử người dùng đặt ra câu hỏi như sau: nguoi(“Socrates”).
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 10
Prolog sẽ tìm mệnh đề đầu tiên có liên quan đến khái niệm nguoi. Và mệnh đề đầu tiên và duy
nhất có liên quan đến khái niệm này là: nguoi(“Socrates”). Như vậy, khi đã có câu hỏi
nguoi(“Socrates”). và tìm thấy mệnh đề liên quan nguoi(“Socrates”)., Prolog sẽ tiến hành tìm
kiếm lời giải. Công việc này tiến hành bằng cách tạo mối liên kết giữa các thông số ở phần câu
hỏi và các thông số ở phần mệnh đề.
Sau khi đã tạo mối quan hệ giữa các thông số ở phần câu hỏi và phần mệnh đề, Prolog sẽ tiến
hành các mệnh đề (nếu mệnh đề này một luật). Nếu tất cả các mệnh đề thành công và các biến ở
phần câu hỏi đã ở tình trạng bound (tức là đã có giá trị), Prolog sẽ thông báo lời giải.
Nếu là câu hỏi thuộc dạng true/false (Yes/No) như ví dụ trên, tức là câu hỏi không chứa biến,
Prolog sẽ trả lời true (Yes) nếu công việc hợp nhất thành công và các mệnh đề đều thành công
(nếu mệnh đề so khớp là một luật).
Ở ví dụ trên, thông số của câu hỏi là một hằng “Socrates”, và thông số của mệnh đề tương ứng
cũng là một hằng “Socrates”. Hai hằng này hợp nhất thành công, và kết quả trả lời là true(Yes).
Nếu người dùng đặt ra câu hỏi khác: nguoi(“Xeda”), Prolog cũng chỉ tìm thấy một mệnh đề liên
quan đến khái niệm này là nguoi(“Socrates”). Vì sự hợp nhất giữa hai hằng “Socrates” và “Xeda”
thất bại nên kết quả sẽ là false(No).
Giả sử câu hỏi có chứa biến: nguoi(X). Hệ thống sẽ tìm thấy mệnh đề có liên quan đến vấn đề này
là nguoi(“Socrates”), rồi tiến hành hợp nhất giữa X và “Socrates”. Vì X chưa có giá trị (unbound)
nên phép hợp nhất thành công. Kết quả X có giá trị là “Socrates”.
Khi việc hợp nhất các thông số giữa phần câu hỏi và phần mệnh đề đã thành công, tất cả các biến
cần tìm đã có giá trị (ở đây chỉ có một biến là X), thì hệ thống sẽ thông báo đã tìm ra lời giải và in
ra giá trị của X ( X = “Socrates”)

Xét trường hợp câu hỏi so khớp với một luật: chet(Y). Câu hỏi được so khớp với mệnh đề sau:
chet(X): - nguoi (X). Vì hai biến X (đối của mệnh đề) và Y (đối của câu hỏi) đều chưa chứa giá
trị, hệ thống sẽ xem cả hai biến là một, nghĩa là khi X có được giá trị thì Y cũng có giá trị đó và
ngược lại.
Quá trình thực hiện các mệnh đề con ở vế phải sẽ được thực hiện như sau:
 Nếu mệnh đề con này có thông số là biến unbound, Prolog sẽ tìm giá trị của biến này để
mệnh đề con có giá trị true(Yes). Nếu không tìm được, mệnh đề con sẽ thất bại.
 Nếu mệnh đề con có đối đều là biến bound (đã có giá trị) hoặc là hằng, Prolog sẽ kiểm tra
xem mệnh đề con có trả về giá trị true(Yes) hay không. Nếu không, mệnh đề con sẽ thất
bại.
Các mệnh đề con sẽ được tiến hành từ trái qua phải, và nếu có một mệnh đề con thất bại, mệnh
đề được so khớp sẽ thất bại.
Ở trường hợp trên, khi tiến hành mệnh đề nguoi(X), vì biến X là unbound (trường hợp 9.1) nên hệ
thống sẽ tìm giá trị của X cho mệnh đề con trên là đúng. Cách tìm kiếm câu trả lời cho mệnh đề
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 11
con này hoàn toàn giống như cách hệ thống tìm câu trả lời khi đặt câu hỏi này trong phần câu hỏi.
Do đó, X sẽ có giá trị là “Socrates”.
Mặt khác, do X và Y được xem như một nên khi X có giá trị là “Socrates” thì Y cũng có giá trị
này và Prolog thông báo là đã tìm ra lời giải và in ra giá trị của Y là: Y=“Socrates”
11. Sự quay lui:
Trong Prolog, phép hợp nhất là chủ đạo. Tuy nhiên, để tìm ra lời giải đúng, Prolog cần phải sử
dụng cơ chế quay lui, khi giá trị đầu tiên được gán cho đối số không phải là lời giải.
Xét ví dụ sau: giả sử có các mệnh đề:
 nguoi(“Socrates”).
 nguoi(“Xeda”).
 vua(“Xeda”).
 sungsuong(X) :- nguoi(X), vua(X).
Trong ví dụ này, ngoài khái niệm về người, còn có khái niệm về vua và sự sung sướng. Ta có thể
diễn giải những thông tin trong các vị từ trên thành ngôn ngữ tự nhiên như sau: "Có hai người tên

là Socrates và Xeda. Một người là vua tên Xeda”. Và một luật là: “một thực thể nào đó chỉ sung
sướng nếu thực thể đó vừa là người vừa là vua."
Giả sử người dùng nhập câu hỏi sau: sungsuong(X) thì Prolog sẽ hiển thị câu trả lời thế nào?
Trước tiên, Prolog sẽ so khớp câu hỏi trên với mệnh đề sungsuong(X) :- nguoi(X),vua(X). Nhưng
khi so khớp câu hỏi với mệnh đề, do cả hai biến X lúc này đều chưa chứa giá trị, nên chúng sẽ
được xem như một.
Sau đó, Prolog sẽ tiến hành các mệnh đề con. Ở mệnh đề con đầu tiên, nguoi(X) tương tự như ví
dụ ở phần trên, Prolog sẽ tìm được câu trả lời là X = “Socrates”. Khi thực hiện mệnh đề con thứ
hai vua(X), lúc này X đã có giá trị là Socrates nên Prolog sẽ kiểm tra xem giá trị này có làm giá
trị của mệnh đề là true hay không.
Việc tiến hành trả lời một mệnh đề con cũng tương tự như khi trả lời một câu hỏi, Prolog lại so
khớp mệnh đề con với một mệnh đề cùng tên. Prolog tìm thấy một mệnh đề liên quan đến vua là
vua(“Xeda”) và tiến hành hợp nhất giữa X và Xeda. Do X đã có giá trị là Socrates, việc hợp nhất
thất bại.
Tuy nhiên, khi mệnh đề con này thất bại, Prolog chưa kết luận vội là mệnh đề này thất bại. Hệ
thống sẽ quay lại thời điểm biến X được gán giá trị, tức là khi trả lời mệnh đề con nguoi(X), X
được chuyển lại sang tình trạng unbound và cố gắng tìm kiếm một giá trị khác của X để cho mệnh
đề con này vẫn đúng. Công việc này được gọi là sự quay lui (back-tracing).
Do việc so khớp mệnh đề con này với mệnh đề nguoi(“Socrates”) thất bại, hệ thống sẽ tiếp tục so
khớp với mệnh đề khác. Nếu không còn mệnh đề nào khác liên quan đến mệnh đề con thì việc
thực hiện mệnh đề mới thật sự thất bại. Ở đây, hệ thống tìm thấy một mệnh đề khác liên quan
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 12
đến khái niệm này là nguoi(“Xeda”). Việc hợp nhất giữa X và Xeda lại được thực hiện, X sẽ có
giá trị là Xeda. Sau đó, khi tiếp tục thực hiện mệnh đề con vua(X) thì mệnh đề con lần này được
thực hiện thành công. Prolog đã tìm ra lời giải. Ta nhận thấy rằng ngoài sự hợp nhất, Prolog còn
sử dụng kỹ thuật quay lui. Và câu trả lời của Prolog cho câu hỏi sungsuong(X). sẽ là X= “Xeda”.
12. Nhát cắt:
Prolog tự động quay lui khi cần tìm một mệnh đề khác để thoả mãn mục tiêu đưa ra. Điều này
rất có ích đối với người lập trình khi cần sử dụng nhiều phương án giải quyết vấn đề. Tuy

nhiên, nếu không kiểm soát tốt quá trình này, việc quay lui sẽ trở nên kém hiệu quả. Vì vậy,
Prolog sử dụng kỹ thuật nhát cắt để kiểm soát quay lui, hay cấm quay lui, đồng thời giúp khống
chế số lời giải nhằm khắc phục khiếm khuyết này.
Ví dụ sau đây minh họa cho một chương trình Prolog sử dụng kỹ thuật quay lui kém hiệu quả.
Giả sử có ba quy tắc để xác định mối liên hệ giữa hai số X và Y:
1. Nếu X < 3 thì Y = 0
2. Nếu X ≤ 3 và X < 6 thì Y = 2
3. Nếu X ≤ 6 thì Y = 4
Và định nghĩa vị từ f( X, Y ) trong Prolog như sau :
f( X, 0) :- X < 3. % luật 1
f( X, 2) :- 3 =< X, X < 6. % luật 2
f( X, 4) :- 6 =< X. % luật 3
Giả sử đặt ra câu hỏi: f(1,Y), 2 < Y.
Lúc này, Y nhận giá trị 0, đích thứ hai trở thành: 2<0, và câu trả lời là false(No) – thất bại. Sau
đó, Prolog tiếp tục cơ chế quay lui để xét cả hai luật còn lại như hình bên dưới:

Vậy để thông báo cho Prolog biết là cần phải dừng ngay điểm nào để tránh sự quay lui không cần
thiết, ta có thể sử dụng nhát cắt. Dấu chấm than ! đại diện cho sử dụng một nhát cắt tại vị trí cần
dừng. Các luật trên thể hiện lại có sử dụng nhát cắt như sau:
 f(X,0):- X<3,!. % luật 1
f(1,Y),2
1<3, 2<0
3≤1, 1<6, 2
6≤1, 2<4
f(1,Y),2
Luật 1
Y=0
Luật 2
Y=2
Luật 3

Y=4
Nhát cắt
Thất bại
Thất bại
Thất bại
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 13
 f(X,2):- 3=<X, X<6, !. % luật 2
 f(X,4):- 6=<X % luật 3
13. Cấu trúc danh sách:
Một danh sách là một dãy bất kỳ các đối tượng. Các đối tượng của danh sách có thể trùng nhau
(xuất hiện nhiều lần), và mỗi vị trí xuất hiện của đối tượng đều có ý nghĩa. Một danh sách trên
Prolog bao gồm 2 phần:
 Phần đầu (head): là phần tử đầu tiên của danh sách.
 Phần đuôi (tail): là danh sách các phần tử còn lại của danh sách.
Danh sách rỗng được mô tả là []. Một danh sách khác rỗng có thể mô tả theo 2 cách sau:
 Liệt kê các phần tử của danh sách.
Ví dụ [1,2,3,4,5].
 Mô tả phần đầu và phần đuôi của danh sách, ngăn cách bởi dấu |
Ví dụ: [1| [2,3,4,5]]
Ví dụ 16:
 Mô tả một danh sách bao gồm 5 số nguyên là 1, 2, 3, 4, 5
 Danh sách trên có thể được mô tả bằng 2 cách như sau:
[1,2,3,4,5]
[1|[2,3,4,5]]
[1|[2|[3,4,5]]]
[1|[2|[3|[4,5]]]]
[1|[2|[3|[4|[5]]]]]
[1|[2|[3|[4|[5|[]]]]]]
Các phần tử của một danh sách có thể là các đối tượng có kiểu bất kỳ, kể cả kiểu danh sách.

Thông thường, phần đuôi của danh sách được xử lý như là một danh sách.
Prolog hỗ trợ một số vị từ cho các thao tác trên danh sách như sau:
Vị từ
Ý nghĩa
append(List1, List2, List3)
Ghép hai danh sách List1 và List2 thành List3.
member(Elem, List)
Kiểm tra Elem có là phần tử của danh sách List
hay không, nghĩa là Elem hợp nhất được với
một trong các phần tử của List.
delete(List1, Elem,List2)
Xoá khỏi danh sách List1 những phần tử hợp
nhất được với Elem để trả về kết quả List2.
select(Elem, List, Rest)
Lấy phần tử Elem ra khỏi danh sách List để trả
về những phần tử còn lại trong Rest, có thể
dùng để chèn một phần tử vào danh sách.
last(List, Elem)
Kiểm tra phần tử đứng cuối cùng trong danh
sách List có phải là Elem hay không.
reverse(List1, List2)
Nghịch đảo thứ tự các phần tử của danh sách
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 14
List1 để trả về kết quả List2.
nth0(Index, List, Elem)
Kiểm tra phần tử thứ Index (tính từ 0) của danh
sách List có phải là Elem hay không.
II. Một số chương trình minh họa bằng Prolog
Phần này trình bày một số chương trình minh họa viết bằng Prolog, cụ thể là sử dụng trình biên

dịch Visual Prolog.
Khai báo các sự kiện (facts):
Trong Visual Prolog, khi khai báo các vị từ, có thể cần chỉ định kiểu (mode) của vị từ. Các mode
này bao gồm:
 single: sự kiện chỉ có một giá trị duy nhất, nếu giá trị khác được thêm vào thì sẽ ghi đè
(overwrite) lên giá trị cũ. Nếu một sự kiện có mode này thì khi gọi luôn nhận được giá trị
đúng.
 determ: sự kiện có thể có một hoặc không có giá trị nào cả. Khi sự kiện không có giá trị
thì khi gọi sẽ trả về thất bại, ngược lại sẽ thành công.
 nondeterm: sự kiện có thể có một hoặc nhiều hoặc không có giá trị nào cả.
Nếu lúc khai báo mà không chỉ định các mode này thì kiểu nondeterm được dùng làm mặc định.
Khai báo vị từ (predicates):
Tương tự như facts, có thể dùng thêm các mode hỗ trợ khi khai báo các vị từ. Các mode bao gồm:
 procedure: vị từ luôn thành công, có một lời giải duy nhất và không có sự quay lui.
 determ: vị từ có thể thành công hoặc thất bại. Nếu thành công thì chỉ có một lời giải và
cũng không có sự quay lui.
 multi: vị từ sẽ không bao giờ thất bại và cho nhiều lời giải.
 nondeterm: vị từ có thể thất bại hoặc thành công và có sự quay lui.
 erroneous: đây là một mode đặc biệt, với mode này thì không có sự thành công cũng như
thất bại. Nó chỉ nêu lên các ngoại lệ (exceptions).
Ví dụ như không tìm thấy tập tin (file cannot be found), tràn bộ nhớ (memory overflow), …
Nếu người dùng không chỉ định mode cho vị từ thì procedure được sử dụng làm mode mặc định.
Khai báo danh sách:
Visual Prolog sử dụng dấu * cho việc khai báo một biến nào đó là kiểu danh sách.
Ví dụ: Khai báo biến mang là danh sách các số nguyên: mang=integer*.
Visual Prolog hỗ trợ hai chế độ thực thi. Đó là console và giao diện người dùng (GUI).
1. Bài toán tháp Hà Nội:
Mô tả bài toán:
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 15

Có một bộ các đĩa kích thước khác nhau, có lỗ ở giữa, nằm xuyên trên ba cái cọc. Bài toán đố bắt
đầu bằng cách sắp xếp các đĩa theo trật tự kích thước vào một cọc sao cho đĩa nhỏ nhất nằm trên
cùng, tức là tạo ra một dạng hình nón.
Yêu cầu của bài toán:
Di chuyển toàn bộ số đĩa sang một cọc khác, tuân theo các quy tắc sau:
 Một lần chỉ được di chuyển một đĩa.
 Một đĩa chỉ có thể được đặt lên một đĩa lớn hơn (không nhất thiết hai đĩa này phải có kích
thước liền kề, tức là đĩa nhỏ nhất có thể nằm trên đĩa lớn nhất).
Thuật giải đệ quy cho bài toán Tháp Hà Nội như sau:
 Đặt tên các cọc là A, B, C. Những tên này có thể chuyển ở các bước khác nhau (ở đây: A
= Cọc Nguồn, B = Cọc Đích, C = Cọc Trung Gian)
 Gọi n là tổng số đĩa.
 Đánh số đĩa từ 1 (nhỏ nhất, trên cùng) đến n (lớn nhất, dưới cùng).
Để chuyển n đĩa từ cọc A sang cọc B thì cần:
1. Chuyển n-1 đĩa từ A sang C. Chỉ còn lại đĩa #n trên cọc A.
2. Chuyển đĩa #n từ A sang B.
3. Chuyển n-1 đĩa từ C sang B cho chúng nằm trên đĩa #n.
Đoạn chương trình viết bằng Prolog cho bài toán Tháp Hà Nội như sau:
predicates
hanoi: (unsigned N)
clauses
hanoi(N):-move(N, “trai”, “giua”, “phai”).
clauses predicates
move: (unsigned N, string A, string B, string C)
clauses
move(0,_,_,_):-!.
move (N,A,B,C):-
move(N-1,A,C,B),
stdio::writef(“Di chuyen mot dia tu cot % sang cot %\n”,A,C),
move(N-1,B,A,C).

goal
hanoi(4).
Kết quả:
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 16

Kết quả sau khi biên dịch và chạy bài toán Tháp Hà Nội
2. Bài toán tính giai thừa:
Mô tả bài toán:
Visual Prolog hỗ trợ chạy chương trình ở 2 chế độ (console và GUI). Ngoài ra, nó còn hỗ trợ xử
lý các luồng nhập, xuất dữ liệu, tương tác người dùng.
Sau đây là một ví dụ về chương trình tính giai thừa của một số nguyên mà hàm tính giai thừa
được định nghĩa dưới dạng một vị từ, và sử dụng kỹ thuật đệ quy cho vị từ này. Vị từ tính giai
thừa được khai báo như sau:
predicates
giaithua:(integer N,integer F) procedure(i,o).
Trong đó:
 N: số nguyên cần tính giai thừa
 F: chứa kết quả
Ở đây, vị từ giai thừa có mode là procedure và (i,o) để chỉ định là đối thứ nhất (N) là input và đối
thứ hai (F) là output.
Phần thân của vị từ để thực hiện tính giai thừa như sau:
clauses
giaithua(0,1) :- !.
giaithua(N, F) :-
N1 = N - 1,
giaithua(N1, F1),
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 17
F = N * F1.

Trong luật thứ nhất cho biết giai thừa của 1 là 1. Luật thứ hai sẽ tính N giai thừa với lời gọi đệ
quy giaithua(N1,F1) và kết quả của F là N*F1, nghĩa là giá trị hiện tại của N nhân với kết quả giai
thừa của N-1 (N1).
Đoạn chương trình sau khi thực thi sẽ cho phép người dùng nhập vào một số nguyên và gọi tới vị
từ giaithua để tính giai thừa và in ra kết quả. Trong Visual Prolog, đoạn chương trình thực hiện
công việc này là vị từ run() được định nghĩa như sau:
clauses
run():-
console::init(),
stdIO::write("Nhap so nguyen duong can tinh giai thua (nhap so am de ket
thuc): "),
hasdomain(integer, N),
N = stdIO::read(),
N >=0, !,
main::giaithua(N, F),
stdIO::write(N,"! = ", F),
stdIO::nl,
_ = stdIO::readchar(),
run().
run().
Kết quả:

Kết quả sau khi biên dịch và chạy chương trình tính giai thừa

Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 18
3. Bài toán gia hệ:
Mô tả bài toán:
Bài toán này nói về các mối quan hệ trong gia đình như cha mẹ, ông bà, tổ tiên. Từ các dữ kiện về
các mối quan hệ này, người dùng có thể đặt ra câu hỏi ai là cha mẹ của X, hay ai là ông bà của

Y,…. Trong chương trình minh họa, chỉ biểu diễn các mối quan hệ: cha mẹ, ông bà, tổ tiên, dựa
trên các vị từ như sau:
person(string Name, gender Gender) %gender là kiểu tự định nghĩa để chỉ giới tính
father(string Person, string Father) %mối quan hệ cha con
mother(string Person, string Mother) %mối quan hệ mẹ con
parent(string Person, string Parent) %mối quan hệ là cha/mẹ
grandFather(string Person, string GrandFather) %mối quan hệ là ông/bà
ancestor(string Person, string Ancestor) %mối quan hệ là tổ tiên
và dựa trên các luật như sau:
parent(Person,Parent):-father(Person,Parent);mother(Person,Parent).
grandFather(Person,GrandFather):-
parent(Person,P1), parent(P1,GrandFather).
ancestor(Person,Ancestor):-parent(Person,Ancestor).
ancestor(Person,Ancestor):-parent(Person,P1), ancestor(P1,Ancestor).
Trên đây là các luật và vị từ làm cơ sở tri thức cho chương trình family đã được cài đặt dưới dạng
giao diện người dùng trên Visual Prolog. Dưới đây là giao diện khi biên dịch và chạy chương
trình:

Giao diện chương trình bài toán gia hệ
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 19
Trước tiên, ta soạn thảo tập tin data.txt với nội dung như sau:

Tiếp theo, nhấn nút và chọn file dữ liệu mẫu data.txt để mở:

Tiếp theo, ta lần lượt click vào 3 nút trên toolbar để xem các thông tin dữ liệu đã
nhập và các mối quan hệ cha mẹ, ông bà, tổ tiên:
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 20


Kết quả xem dữ liệu của các vị từ
Ngoài ra, ta có thể chọn lệnh trong menu Xem để biết thông tin về một người nào đó có cha mẹ,
ông bà, tổ tiên là ai.
Xem thông tin cha mẹ:
Khi hộp thoại Xem cha mẹ xuất hiện, ta nhập tên người cần xem thông tin, và nhấn nút Xem.
như hình sau:

Xem thông tin cha mẹ của người tên Minh
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 21
Xem thông tin ông bà:

Xem thông tin ông bà
Xem thông tin tổ tiên:

Xem thông tin tổ tiên của người tên Vinh
Muốn thêm thành viên mới, ta chọn menu Thêm. Khi hộp thoại Thêm thành viên xuất hiện, ta
nhập thông tin của thành viên mới vào.

Hộp thoại Thêm thành viên
Cuối cùng, ta nhấn nút Save để lưu lại thông tin thành viên mới trong tập tin data.txt đã mở.

Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 22
Tài liệu tham khảo

[1] PGS. TS. Đỗ Văn Nhơn, bài giảng Biểu diễn tri thức và suy luận, 2014
[2] Phan Huy Khánh, Lập trình logic trong Prolog, NXB ĐHQG Hà Nội, 2004.
[3] ThS. Nguyễn Văn Linh, Ngôn Ngữ Lập Trình, ĐH Cần Thơ, 12/2003.
[4]

[5]
[6]
Biểu diễn tri thức và suy luận
Hồ Viết Quang Thạch – CH1301052 GVHD: PGS.TS. Đỗ Văn Nhơn Trang 23
Mục lục
Lời nói đầu 1
I. Ngôn ngữ Prolog 2
1. Giới thiệu 2
2. Các thuật ngữ 2
3. Các kiểu dữ liệu 3
4. Chú thích 3
5. Biến 3
6. Phép toán số học 3
7. Sự kiện và luật 4
8. Chương trình Prolog 5
9. Phép hợp nhất 8
10. Cơ chế tìm câu trả lời của Prolog 9
11. Sự quay lui 11
12. Nhát cắt 12
13. Cấu trúc danh sách 13
II. Một số chương trình minh họa bằng Prolog 14
1. Bài toán tháp Hà Nội 14
2. Bài toán tính giai thừa 16
3. Bài toán gia hệ 18

×