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

Tài liệu PROLOG FAST FOOT pdf

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 (468.44 KB, 31 trang )

Prolog Fast Foot Prolog Fast Foot .
NỘI DUNG

HƯỚNG DẪN 2
ĐẶC ĐIỂM CỦA PROLOG 5
CẤU TRÚC CỦA CHƯƠNG TRÌNH PROLOG 6
DOMAINS 7
PREDICATES 9
CLAUSES 10
GOAL 13
ĐẶC ĐIỂM CỦA BIẾN 14
BẢN CHẤT ĐỆ QUI 15
KIỂU DANH SÁCH 17
NGUYÊN TẮC TRẢ LỜI GOAL 20
CƠ CHẾ HOẠT ĐỘNG CỦA PROLOG 23
LẬP TRÌNH LUẬN LÝ − MÔ TẢ 30
LẬP TRÌNH LUẬN LÝ − ĐỆ QUI 34
TẠP LUẬN 45
LỊCH SỬ 59
TÀI LIỆU THAM KHẢO 62 
HƯỚNG DẪN

Thức ăn nhanh giúp người ta nhanh chân hơn trong việc giành lấy cơ
hội. Nhưng cũng rất nguy hiểm - nếu lạm dụng. Hãy thận trọng và ý
thức. Mọi tấm huy chương đều có mặt trái. Nhưng tốt nhất là đừng lật
mặt trái của nó lên.
Hãy nhớ rằng ngôn ngữ là phương tiện, bất kể nó là loại ngôn ngữ nào.
Nội dung truyền đạt quan trọng hơn là cách thức truyền đạt.
Tài liệu này cung cấp một số kiến thức cơ bản, giúp cho người đọc hiểu
được quan điểm lập trình luận lý (logic programming). Cung cách lập
trình này có khác với loại lập trình cấu trúc thường gặp trong các ngôn


ngữ Pascal, C, Fortran, … . Vì vậy việc làm quen với một phong cách
mới cần phải có thời gian. Thời gian để quên cái cũ. Do đó tài liệu này
cố tránh né việc trình bày dưới góc độ cấu trúc. Tuy nhiên cũng đã có
đôi lúc vì sự cám dỗ của người đọc mà lại sa đà vào. Và cũng hy vọng
rằng, đây cũng như là sự cám dỗ cuối cùng của chúa.
Một bài toán từ khi đặt ra cho đến khi có được lời giải phải thực hiện
một khối lượng công việc là M. Dù bài toán được giải bằng ngôn ngữ
lập trình nào thì khối lượng vẫn là M. Ai sẽ đảm nhiệm khối lượng này
?. Người lập trình đương nhiên sẽ phải đảm nhiệm một phần, phần còn
lại do hệ thống gánh vác. Như vậy người lập trình trong hệ thống phải
biết phần việc nào mình làm và phần việc nào mình không làm. Đây
chính là hành vi cần phải nhận thức. Sự phân chia này sẽ rất khác nhau
ở các ngôn ngữ lập trình. Người lập trình trong hệ thống Prolog luôn là
một ông chủ nhàn hạ vì hệ thống Prolog là một người thích ôm lấy
công việc. Còn lập trình cấu trúc thì không như vậy, hệ thống của các
ngôn ngữ cấu trúc luôn “thụ động”. Nó chỉ làm việc với sự chỉ bảo của
người lập trình.
N.T. Son 1 2 N.T. Son
Vậy người lập trình Prolog sẽ làm gì ?. Họ chỉ cần mô tả bài toán theo
qui định của luận lý (logic). Nghĩa là dùng các câu khai báo để mô tả
Prolog Fast Foot Prolog Fast Foot .
bài toán. Ngoài ra không cần làm thêm gì cả, hệ thống Prolog sẽ đảm
nhiệm hết phần còn lại.
Phải quên đi một thói quen là một hành vi thường gặp trong các
hoạt động nghiên cứu khoa học. Đây chính là xóa bỏ định kiến.
Học tập ngoài mặt tốt của nó còn có một khía cạnh khác là hình
thành định kiến. Như vậy định kiến là điều không thể tránh khỏi
trong quá trình học tập. Vì vậy hãy chọn lựa phương pháp học tập
sao cho phần định kiến được giảm thiểu. Lập trình luận lý sẽ
phần nào giúp chúng ta giải quyết được bài toán này.

N.T. Son 3 4 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
ĐẶC ĐIỂM CỦA PROLOG
• Prolog không phân biệt giữa khái niệm Data và Program
như trong Pascal.
• Sức mạnh của Prolog là đệ qui.
• Toàn bộ chương trình được xem như một cơ sở tri thức
(knowledgebase).
• Chương trình Prolog là một tập hợp các luật (rules).
• Prolog là ngôn ngữ được thiết kế chủ yếu cho các suy luận,
không coi trọng tính toán.
• Kowalski nói Algorithm = logic+control.
Logic là phát biểu về cái gì bài toán phải giải quyết.
Control phát biểu về làm thế nào bài toán được giải quyết.
• Người lập trình luận lý chỉ phải thực hiện phần logic còn
phần control hệ thống sẽ đảm nhiệm.






CẤU TRÚC CỦA CHƯƠNG TRÌNH PROLOG
• Domains, Predicates, Clauses, Goal.
• Hệ thống prolog cung cấp sẵn một số tập hợp để người lập
trình sử dụng : Integer, Char, Real, Symbol, String, … .
• Hệ thống prolog cũng cung cấp cho người lập trình khả
năng tạo ra các tập hợp mới phù hợp với bài toán cần giải.
• Domains là nơi để người lập trình định nghĩa những tập
hợp mới (hoặc đặt tên lại).

• Predicates là phần khai báo các quan hệ giữa các domains.
• Clauses là phần định nghĩa các quan hệ đã khai báo trong
phần predicates.
• Clauses gồm các rule. Rule được dùng để biểu diễn cho câu
khai báo có dạng điều kiện - if nguyên_nhân then hậu_quả.
Nếu rule không có nguyên nhân thì được gọi là sự kiện
(fact). Do đó fact là hậu quả tất yếu xảy ra không không
cần một nguyên nhân nào.
• Goal là phần đặt câu hỏi đối với hệ thống.
DOMAINS
• Nơi tạo tập hợp mới có cùng kiểu với tập hợp có sẵn.
Thí dụ :
Domains
Tên = symbol
Tuổi = integer
NghềNghiệp = symbol
Chú thích :
1. Một số kiểu (tập hợp) cơ bản :
integer : kiểu số nguyên,
N.T. Son 5 6 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
real : kiểu số thực,
char : kiểu ký tự,
string : kiểu chuỗi, gồm chuỗi các ký tự có chiều dài
‘tuỳ ý’ được đặt giữa hai dấu nháy.
symbol : là kiểu gồm những ký hiệu, mỗi ký hiệu có
chiều dài tối đa 255 ký tự, bắt đầu bằng ký tự
thường.
2. Dù miền Tên và miền NghềNghiệp có cùng kiểu symbol
nhưng chúng không so sánh hoặc đồng nhất được với

nhau. Nói chung là các tập hợp trong Domains nếu
không cùng tên thì sẽ không tương thích với nhau.
• Tạo tập hợp là tích các tập hợp.
Thí dụ :
Domains
Ấnphẩm = Tạpchí(symbol, symbol)
TiểuSử = LýLịch(symbol, integer, symbol, symbol)
• Tạo tập hợp là hội các tập hợp.
Thí dụ :
Domains
Tên = symbol
Tàiliệu = Book(Tên,Tên) or Magazine(Tên,Tên)
Dấu = âm ; dương ; Kýsố(integer)
Hội hai tập hợp bằng ký hiệu OR hoặc CHẤM PHẨY.
Tập hợp thành phần của hội có thể là tập hợp có một phần
tử. Thí dụ âm, dương là hai tập hợp có một phần tử.
N.T. Son 7 8 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
PREDICATES
• Tạo quan hệ giữa các tập hợp.
Thí dụ :
Domains
Tên = symbol
Nghềnghiệp = string
Tuổi = integer
Predicates
Lýlịch(Tên, Tuổi, Nghềnghiệp)
• Tạo quan hệ trống.
Thí dụ :
Predicates

Repeat()
Khôngmàu
Repeat và Khôngmàu là tên của hai quan hệ. Tập hợp mà
nó quan hệ là tập trống. Quan hệ Repeat() còn có thể viết là
Repeat. Quan hệ Khôngmàu có thể viết là Khôngmàu().




CLAUSES
• Biến và hằng
Turbo Prolog qui định biến có ký tự bắt đầu là ký tự in
(upppercase) hoặc ký tự gạch dưới (underscore). Hằng có ký
tự bắt đầu là ký tự thường (lowercase).
Thí dụ :
Minh, X, Người, _minh, _x, _người … là 6 biến.
minh, x, người, … là 3 hằng.
• Fact
Fact là một quan hệ trên các tập hợp đã xác định (có sẵn
hoặc đã được xác định trong Domains).
Đây là cách xác định tập hợp bằng liệt kê.
Thí dụ :
Predicates
Chơi(symbol, symbol)
Biết(symbol, symbol)
Clauses
Chơi(sơ, piano). Chơi(kính, violon).
Chơi(tân, keyboard). Chơi(trang, guitare).
Chơi(sơ, guitare). Chơi(kính, piano).
Biết(sơ, vẽtranh). Biết(kính, làmthơ).

Biết(kính, điêukhắc). Biết(kính, soạnnhạc).
• Rule
Rule là quan hệ được định nghĩa từ nhiều quan hệ khác.
Đây là cách xác định tập hợp bằng phương pháp trưng tính.
N.T. Son 9 10 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
Rule có dạng của câu điều kiện, nghĩa là gồm nguyên nhân
và hậu quả (nguyên nhân → hậu quả). Tuy nhiên Rule là
câu điều kiện được trình bày theo dạng thức : Hậu quả
← nguyên nhân.
Các dạng sau đây tương đương :
Hậu quả ← Nguyên nhân hay
Hậu quả if Nguyên nhân hay
Hậu quả :- Nguyên nhân.
Do đó Fact có thể được xem là một loại rule đặc biệt - rule
không có điều kiện.
Nếu mệnh đề nguyên nhân gồm 3 mệnh đề nguyên nhân
ngnh1, ngnh2 và ngnh3 kết hợp lại thì được biểu diễn như
sau :
Nguyên nhân = Ngnh1 and Ngnh2 and Ngnh3.
Hoặc
Nguyên nhân = Ngnh1, Ngnh2, Ngnh3.

Thí dụ :
Predicates
Chơi(symbol, symbol) /* định nghĩa ở trên */
Biết(symbol, symbol) /* định nghĩa ở trên */
Đanăng(symbol)
Clauses
Đanăng(X) :- Biết(X, Y), Chơi(X, Z).

Một học sinh X đa năng nếu biết ít nhất một môn nghệ
thuật Y và chơi được một môn thể thao Z.
Thí dụ :
Chuyển đổi tam đoạn luận sang Prolog :
Mọi người đều phải chết.
Socrates là người.
Vậy Socrates phải chết.
Predicates
Làngười(symbol)
Chết(symbol)
Clauses
Làngười(socrates).
Chết(Ai) :- Làngười(Ai).

Nhận xét :
Một predicates được định nghĩa trong clauses bằng nhiều fact
hoặc nhiều rule hoặc kết hợp vừa fact vừa rule.
Thí dụ :
Xác định tập hợp A = {1,2,3,4,5,6,8,10,12,14, … }
Predicates
PtửA(integer)
Clauses
N.T. Son 11 12 N.T. Son
PtửA(1).
Prolog Fast Foot Prolog Fast Foot .
PtửA(3).
PtửA(5).
PtửA(X) :- (X mod 2) = 0.
Vị từ PtửA được định nghĩa gồm 3 fact và 1 rule.


GOAL
• Goal là nơi đặt câu hỏi với hệ thống và hệ thống sẽ cho câu
trả lời.
• Goal gồm một hay nhiều predicates cùng với thông số. Nếu
goal gồm nhiều thành phần thì mỗi thành phần được gọi là
subgoal.
Thí dụ :
Cho hệ thống tam đoạn luận như thí dụ ở trên. Khi đó có
thể đặt 1 trong 5 câu hỏi sau :
Goal Chết(Ai).
Goal Chết(socates).
Goal Làngười(Ai).
Goal Làngười(socrates).
Goal Chết(Ai), Làngười(socrates).
Bốn Goal đầu có 1 subgoal. Nhưng goal cuối có 2 subgoal
là Chết(Ai) và Làngười(socrates).

ĐẶC ĐIỂM CỦA BIẾN TRONG TURBO PROLOG
• Biến trong mỗi clauses phải xuất hiện ít nhất 2 lần.
• Nếu biến chỉ xuất hiện một lần trong clauses thì phải thay
nó bằng biến rỗng (anonymous). Ngoài ra một thông số
nào của vị từ trong clauses mà ta không quan tâm cũng có
thể thay nó bằng biến rỗng.
• Biến rỗng được biểu diễn bằng ký hiệu gạch dưới _
(underscore).


Thí dụ :
Clauses
Đanăng(X) :- Biết(X, Y), Chơi(X, Z).

Biến Y và Z chỉ xuất hiện 1 lần nên phải đổi thành biến
rỗng. Do đó :
Clauses
Đanăng(X) :- Biết(X, _ ), Chơi(X, _ ).
• Các trạng thái của biến là : tự do (free), bị trói (bound),
được cởi (unbound). Các trạng thái này do hệ thống thực
hiện. Người lập trình không có bất kỳ tác động nào lên biến
để thay đổi trạng thái. Do đó Prolog không có hành động
gán (assignment) giá trị cho biến như trong ngôn ngữ
Pascal.
N.T. Son 13 14 N.T. Son
Prolog Fast Foot Prolog Fast Foot .

BẢN CHẤT ĐỆ QUI
Vì Prolog không phân biệt giữa dữ liệu và chương trình như
Pascal nên vấn đề đệ qui được thực hiện cả trong domains và
clauses.
Nền tảng toán học của đệ qui là định lý truy chứng. Việc áp
dụng đệ qui trong Prolog sử dụng cả 2 dạng truy chứng.
Dạng 1 :
P
1
.
P
n
→ P
n+1
.
Dạng 2 :
P

1
.
P
m
→ P
n+1
, với m ∈ [1, n].
Trong thực tế mệnh đề P
1
của truy chứng tương ứng với một
tập hợp các mệnh đề sự kiện (fact).
Mệnh đề P
n
→ P
n+1
cũng tương ứng với một tập hợp các mệnh
đề qui luật (rule).
• Đệ qui trong khai báo Domains
Thí dụ :
Domains
Cây = Tree(symbol, Cây); Trống
Miền Cây là hội của hai tập hợp. Tập hợp thứ nhất chỉ có
một phần tử là Trống và tập hợp thứ hai là tập hợp đệ qui
Tree(symbol, Cây).


• Đệ qui trong phần clauses
Thí dụ :
Tính giai thừa của một số nguyên.
Giai thừa của 5 là 5 ! = 1×2×3×4×5. Như vậy để tính giai

thừa của 5 thì tính giai thừa của 4 (=5–1). Sau đó lấy kết
quả nhân với 5.
Vậy 5 ! = 4! × 5.
Predicates
Giaithừa (real, real)
Clauses
Giaithừa(1,1).
Giaithừa(N,T) :- M=N–1, Giaithừa(M,S), T=S*N.
Tập hợp thứ nhất gồm một mệnh đề sự kiện là
Giaithừa(1,1) và tập hợp một mệnh đề đệ qui là
Giaithừa(N,T) :- M=N –1, Giaithừa(M, S), T = S*N.

N.T. Son 15 16 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
KIỂU DANH SÁCH
Đây là một loại tập hợp có bản chất đệ qui. Do đó những thao
tác trên danh sách cần khai thác tính đệ qui triệt để.
• Danh sách là một loại tập hợp có phần tử là chuỗi các phần
tử của một tập hợp trong miền Domains.
• Kiểu danh sách của Prolog được định nghĩa bằng cách thêm
ký tự * vào tên kiểu phần tử.
Thí dụ :
Domains
Họtên = symbol
DsSV = Họtên*
DsSố = integer*
DsTên = symbol*
DsNghềnghiệp = string*
DsSV là danh sách các phần tử mà mỗi phần tử có kiểu
Hotên.

DsSố là danh sách các phần tử mà mỗi phần tử là số
nguyên.
• Dạng thức của một biến kiểu danh sách :
− Liệt kê : các phần tử của danh sách đặt cách nhau
bằng dấu phẩy. Tất cả đặt ở giữa 2 dấu móc vuông.
Thí dụ :
Domains
Dssố = integer*
Biến X có kiểu Dssố là một danh sách 4 số nguyên
1, 2, 3, 4, được viết như sau :
X = [1,2,3,4]
− Đệ qui : Danh sách được biểu diễn gồm 2 phần, phần
Head gồm 1 phần tử đầu của biểu diễn liệt kê và phần
Tail gồm những phần tử còn lại của biểu diễn liệt kê.
Phần Tail được biểu diễn bằng một danh sách liệt kê
khác. Head và Tail đặt cách nhau dấu sổ xuống. Head
và Tail được đặt trong dấu móc vuông.
Thí dụ :
Domains
Dssố = integer*
Biến X có kiểu Dssố là một danh sách 4 số nguyên
1, 2, 3, 4, được viết như sau :
X = [1|[2,3,4]].
− Một số danh sách đặc biệt :
a. Danh sách trống [] có head và tail không được
định nghĩa.
b. Danh sách [1,2,3,4] = [1|[2,3,4]] có head là 1,
tail là [2,3,4].
c. Danh sách [1] = [1|[] ] có head là 1, tail là danh
sách trống [].

N.T. Son 17 18 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
d. Danh sách [[1,2,3], [2,3,4,5], [6]] =
[[1,2,3]|[[2,3,4,5], [6]]] có head là [1,2,3] và tail
là [[2,3,4,5],[6]].

NGUYÊN TẮC TRẢ LỜI GOAL CỦA PROLOG
• Tuần tự từ trên xuống : hệ thống sẽ trả lời cho subgoal
đầu tiên, kế đến là subgoal thứ 2, thứ 3, … cho đến
subgoal cuối cùng.
N.T. Son 19 20 N.T. Son
• So trùng (matching) : để trả lời cho từng subgoal hệ thống
dò subgoal tuần tự theo từng dòng trong clauses. Việc dò
tìm sẽ dừng khi subgoal trùng với một dòng clause nào đó,
nếu không trùng thì dò tiếp cho đến dòng cuối cùng của
clauses.
Thí dụ : Tháp Hà Nội.
Đừng cố tìm hiểu ý nghĩa của chương trình này, chỉ cần
quan sát hình thức của nó.
Các ký hiệu ! và nl là các subgoal.
Domains
Cột = symbol
Predicates
Hanoi
Hanoi(integer)
Dời(integer, Cột, Cột, Cột)
Msg(Cột, Cột)
Clauses
Hanoi :- Hanoi(5). (1)
Hanoi(N) :- Dời(N, trái, giữa, phải). (2)

Dời(1, A, _, C) :- Msg(A, C), !. (3)
Dời(N, A, B, C) :- (4)
M = N-1,
Dời(M, A, C, B),
Msg(A, C), !,
Dời(M, B, A, C).
Msg(Loc1, Loc2) :- (5)
write("Dời đĩa từ ", Loc1, " vào", Loc2), nl, !.
Goal
Hanoi.
Mô tả cấu trúc chương trình :
1. Sử dụng 2 miền : Cột và integer.
2. Khai báo 4 vị từ :
vị từ Hànội không có thông số,
vị từ Hànội có 1 thông số,
vị từ Dời có 4 thông số,
vị từ Msg có 2 thông số.
3. Phần định nghĩa của các vị từ trong clauses :
vị từ Hànội có 1 mệnh đề,
vị từ Hànội(_) có 1 mệnh đề,
Prolog Fast Foot Prolog Fast Foot .
vị từ Dời(_,_,_,_) có 2 mệnh đề,
vị từ Msg(_,_) có 1 mệnh đề.
Để thỏa mãn Goal Hanoi, hệ thống sẽ dò tuần tự từ mệnh
đề đầu tiên đến mệnh đề thứ 5 trong phần clauses.
Goal Hanoi trùng với phần đầu của mệnh đề 1
Hanoi :- Hanoi(5).
Để thỏa mãn mệnh đề này thì subgoal Hanoi(5) phải được
thoả. Khi đó hệ thống sẽ dò trong 5 mệnh đề xem mệnh đề
nào trùng với Hanoi(5) :

Với mệnh đề 1, Hanoi(5) không so trùng được vì
phần đầu của mệnh đề 1 là Hanoi (không có thông
số) còn Hanoi(5) có một thông số.
Với mệnh đề 2, Hanoi(5) so trùng được vì phần đầu
của mệnh đề 1 là Hanoi(N). Lúc này N bị buộc
vào giá trị 5. Để mệnh đề này được thỏa thì điều
kiện Dời(N,trái,giữa,phải) của mệnh đề 2 cần phải
được thỏa mãn. Hệ thống lại dò trong 5 mệnh đề
và thấy rằng điều kiện này trùng với mệnh đề 3.
Do đó điều kiện của mệnh đề 3 Msg(A, C) cũng
phải được thỏa.
Quá trình này diễn tiến cho đến khi không còn điều
kiện nào đòi hỏi thì hệ thống dừng.

CƠ CHẾ HOẠT ĐỘNG CỦA PROLOG
• Đồng nhất (unification). Khi so trùng subgoal với các
dòng của clauses hệ thống prolog áp dụng cơ chế đồng
nhất.
− Nếu subgoal so trùng với một dòng của clauses là fact
thì nó sẽ đồng nhất tên vị từ kế đến là danh sách
thông số. Các thông số sẽ được đồng nhất theo dạng
thức.
Thí dụ :
Predicates
Chếtạo(symbol, symbol)
Clauses
Chếtạo(minh, tênlửa). (1)
Chếtạo(dũng, máytính). (2)
Chếtạo(thư, xehơi). (3)
Goal

Chếtạo(thư, X).
Prolog sẽ trả lời bằng cách dò trên 3 mệnh đề của
phần clauses.
Với mệnh đề 1 Chếtạo(minh, tênlửa) :
tên vị từ phù hợp cùng là Chếtạo,
cùng có 2 thông số,
N.T. Son 21 22 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
nhưng thông số thứ 1 của goal là thư khác với
thông số thứ 1 của mệnh đề 1 là minh. Do đó
mệnh đề này không phù hợp với goal. Việc so
trùng tiếp tục.
Với mệnh đề 2 Chếtạo(dũng, máytính) :
tên vị từ phù hợp cũng là Chếtạo,
cùng có 2 thông số,
nhưng thông số thứ 1 của goal là thư khác với
thông số thứ 1 của mệnh đề 1 là dũng. Do đó
mệnh đề này không phù hợp với goal. Việc so
trùng tiếp tục.
Với mệnh đề 3 Chếtạo(thư, xehơi) :
tên vị từ phù hợp cũng là Chếtạo,
cùng có 2 thông số,
thống số thứ 1 giống nhau cùng là thư,
thông số thứ 2 của goal là biến X chưa có giá trị
nên đồng nhất với thông số thứ 2 là xehơi. Vậy
hệ thống sẽ trả lời X là xehơi.
− Nếu subgoal so trùng với một dòng của clauses là rule
thì nó đồng nhất tên, kế đó đồng nhất dạng thức thông
số. Cuối cùng là kiểm tra các subgoal diên tả điều kiện
có trong mệnh đề đó.

Thí dụ :
Domains
Dssố = integer*
Predicates
Sub(Dssố, Dssố)
Clauses
Sub( [], _ ) :- subgoal, … . (1)
Sub( [_|[3|Y]], [] ) :- subgoal, … . (2)
Sub( X, [2|[3,4]] ) :- subgoal, . (3)
Goal
Sub([5], [Y|[3]] ).
Để thoả mãn goal, hệ thống sẽ tiến hành dò từ mệnh
đề 1 đến mệnh đề 3.
Với mệnh đề 1, ở thông số 1 có [] ≠ [5].
Với mệnh đề 2, ở thông số 1 có _ = [5] nhưng [3|Y]]
≠ [],
Với mệnh đề 3, ở thông số 1 có X = [5], ở thông số 2
có Y = 2 và [3,4] ≠ [3] (vì danh sách [3,4] có 2
phần tử còn danh sách [3] chỉ có 1 phần tử),
Hệ thống trả lời là không đáp ứng được goal này mặc
dù chưa hề kiểm tra đến các subgoal.
Nhận xét :
Sự khác biệt giữa rule của Prolog và if … then của Pascal.
If Điềukiện then Kếtquả = lệnh điều kiện của Pascal.
N.T. Son 23 24 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
Kếtquả if Điềukiện = Rule của Prolog.
Hệ thống Pascal khi thực hiện lệnh if-then sẽ kiểm tra điều
kiện trước, nếu đúng mới thực hiện kết quả. Nhưng với rule
của Prolog thì kết quả được kiểm tra trước. Việc kiểm tra

được thực hiện gồm hai phần - dạng thức và giá trị. Khi
dạng thức và giá trị phù hợp thì hệ thống mới kiểm tra điều
kiện (các subgoal).
Trong một số trường hợp trình tự thực hiện này của Prolog
có tiện lợi, vì nếu hình thức kết quả không phù hợp thì
không cần thiết kiểm tra điều kiện. Trong khi Pascal việc
kiểm tra điều kiện và hình thức kết quả đươc gom chung
vào trong điều kiện.
• Thối lui (backtracking)
− Giả sử có mệnh đề P :- P
1
, P
2
, P
3
. Muốn mệnh đề P
thỏa thì các subgoal P
1
, P
2
, P
3
phải thỏa. Giả sử P
1
thỏa
nhưng còn 5 trường hợp chưa xét đến. Khi đó hệ thống
sẽ kiểm tra xem P
2
có thoả hay không. Nếu P
2

không
thỏa thì hệ thống sẽ thối lui lại để kiểm tra P
1
với 5
trường hợp chưa xét. Việc này thực hiện được nhờ cơ
chế thối lui của Prolog.
• Các trạng thái của biến
− Tự do (free) : Trước khi bị buộc thì biến được gọi là
tự do.
− Bị trói (bound) : Khi biến được đồng nhất thì nó bị
buộc giá trị được đồng nhất vào.
− Được cởi (unbind) : Khi backtracking tại vị từ nào thì
biến trong thông số của vị từ đó được cởi bỏ giá trị đã
mang trước đó ra, và từ lúc này nó được tự do và chờ
để bị buộc giá trị mới vào.
Thí dụ :
Predicates
Chơi(symbol, symbol)
Biết(symbol, symbol)
Đanăng(symbol)
Clauses
Chơi(minh, piano). Chơi(kính, violon).
Chơi(tân, keyboard). Chơi(trang, guitare).
Biết(tân, vẽtranh). Biết(kính, làmthơ).
Biết(kính, điêukhắc). Biết(kính, soạnnhạc).
Đanăng(X) :- Biết(X, _), Chơi(X, _).
Goal
Đanăng(X).
Để goal thỏa thì 2 subgoal Biết(X,_) và Chơi(X,_) phải
thỏa.

N.T. Son 25 26 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
Subgoal Biết(X, _ ) sẽ được duyệt trên clauses và sẽ lấy
giá trị là Biết(tân, vẽtranh) và còn 3 mệnh đề mà subgoal
này chưa duyệt.
Kế đó subgoal Chơi(tân, _ ) (biến X không còn tự do đã
bị buộc vào giá trị tân) được duyệt nhưng không có
mệnh đề nào để nó thỏa vì vậy nó thất bại. Hệ thống sẽ
tự thối lui đồng thời biến X được cởi bỏ giá trị tân, nó
trở lại trạng thái tự do và dò trở lại subgoal Biết(X, _)
với 3 mệnh đề còn lại. Như vậy sẽ lấy giá trị Biết(kính,
làmthơ). Subgoal Chơi lại được dò trùng để lấy giá trị.
Nó lấy được giá trị Chơi(kính, violon). Khi đó goal đã
được thỏa và biến X của vị từ Đanăng lấy giá trị là
kính.
Chú ý :
Biến trong Prolog chỉ có ý nghĩa trong mệnh đề chứa nó.
Do đó nhiều mệnh đề khác nhau có thể có cùng tên biến.




LẬP TRÌNH LUẬN LÝ – MÔ TẢ
Một việc khó khăn cho người lập trình Prolog là nếu họ đã quá
quen thuộc với lập trình cấu trúc. Kinh nghiệm này gây nhiều
bất lợi hơn là thuận lợi. Lập trình prolog có thể hình dung
bằng hai từ : mô tả và đệ qui.
Những hướng dẫn sau giúp cho người lập trình quên đi thói
quen lập trình cấu trúc.
• Hãy mô tả bài toán lại thành các câu khai báo.

Cần nhận dạng ra các câu điều kiện và các câu chỉ sự kiện.
Thí dụ :
Dạng ban đầu của bài toán :
Mọi người có sách đều có thể cho Trang mượn. Biết
rằng Tâm có một quyển sách.
Hỏi rằng Tâm có thể cho Trang mượn sách hay
không ?
Dạng câu khai báo :
- Nếu ai có sách thì cho Trang mượn sách.
- Tâm có sách.
- Tâm cho Trang mượn sách ?
• Nhận dạng các quan hệ.
Để nhận dạng ra các quan hệ bằng cách chọn trong các
động từ của các câu khai báo. Còn đối tượng của quan hệ
chính là các danh từ.
Khi động từ là thì chọn quan hệ là tính từ đi theo nó.
Thí dụ : (tiếp theo)
Các động từ : Có, Chomượn.
N.T. Son 27 28 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
Các đối tượng :
ai (có sách), người (cho mượn),
người (được cho mượn), sách.
Có thể chuyển thành các quan hệ :
Cósách(người), (1)
Có(Ai, Cái_sở_hữu), (2)
Chomượnsách(Ai_cho, Ai_mượn), (3)
Chomượn(Ai_cho,Ai_mượn,Cái_được_mượn) (4)
Như vậy có nhiều lựa chọn để mô tả bài toán :
a. (1) & (3).

b. (1) & (4).
c. (2) & (3).
d. (2) & (4).
Dữ liệu cụ thể với tất cả quan hệ trên :
Cósách(tâm),
Có(tâm, sách),
if Cósách(Ai) then Chomượnsách(Ai, trang),
if Có(Ai, sách) then Chomượn(Ai, trang, sách),
Chomượnsách(tâm, trang) ?,
Chomượn(tâm, trang, sách) ?.
Như vậy dựa vào đâu để có quyết định có một lựa chọn
?.
- Dựa vào các đối tượng cụ thể.
Nếu đối tượng trừu tượng chỉ có một đối tượng cụ thể
thì ghép nó vào quan hệ. Đối tượng trừu tượng Cáigì chỉ
có một đối tượng cụ thể là sách nên ta ghép sách vào các
động từ tương ứng.
Do đó chỉ còn có các quan hệ :
Cósách(người), (1)
Chomượnsách(Ai_cho, Ai_mượn), (3)
• Chuyển thành fact và rule.
Khi chuyển câu điều kiện thành rule nhớ đảo ngược vị trí –
hệ quả đặt phía trước và nguyên nhân đât ở sau.
Thí dụ : (tiếp theo)
if Cósách(Ai) then Chomượnsách(Ai, trang),
Cósách(tâm),
Chomượnsách(tâm, trang) ?,
Thí dụ :
a. Dạng ban đầu : Người nào kính trọng mình thì được
người khác kính trọng. Trang kính trọng mình. Ai được

Tâm kính trọng ?.
b. Dạng khai báo :
- Nếu mình kính trọng mình thì người khác kính trọng
mình.
- Trang kính trọng Trang.
- Tâm kính trọng ai ?.
N.T. Son 29 30 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
N.T. Son 31 32 N.T. Son
c. Chọn quan hệ :
- động từ : KínhTrọng,
- đối tượng : người, Trang, Tâm. Các đối tượng đều
thuộc lớp đối tượng trừu tượng là Người.
d. Chuyển thành fact và rule :
Nếu KínhTrọng(X, X) thì KínhTrọng(Y, X),
KínhTrọng(trang, trang), KínhTrọng(tâm, Ai).
e. Dạng Prolog tương ứng :
KínhTrọng(Y, X) :- KínhTrọng(X, X).
KínhTrọng(trang, trang).
Goal KínhTrọng(tâm, Ai).
LẬP TRÌNH LUẬN LÝ – ĐỆ QUI
Để lập trình đệ qui thì trước hết vẫn phải thực hiện phần lập
trình mô tả. Sau đó chọn các câu khai báo có bản chất truy
chứng để chuyển thành dạng đệ qui. Một câu khai báo được
gọi là có bản chất truy chứng khi có thể biến đổi thành tương
đương với vô hạn câu khai báo. Trong thực tế một câu khai
báo có bản chất truy chứng có thể có nhiều dạng tương đương
truy chứng. Các thí dụ sau sẽ minh họa điều này. Lý thuyết tập
hợp cho chúng ta biết có hai dạng truy chứng hữu hạn. Lập
trình luận lý sử dụng cả 2 dạng này.

Về việc nhận dạng các câu khai báo có thể đọc thêm ở tài liệu
tham khảo [9]. Về các kỹ thuật chuyển một câu sang dạng truy
chứng có thể xem phụ chương 4 của tài liệu tham khảo [10].
Thí dụ : Phần tử của một danh sách.
Qui ước L[n] là danh sách L có chiều dài n.
a. Dạng nguyên thủy :
P = “X là phần tử X của danh sách L”.
b. Biến đổi P tương đương với vô hạn mệnh đề P
n
:
P = (∀n)P
n
,
với P
n
= “X là phần tử của danh sách L[n] ”.
c. Dạng truy chứng 1 :
P
1
.
P
n
→ P
n+1
.
d. Dạng truy chứng tương đương với hai mệnh đề :
X là phần tử của L[1].
Nếu X là phần tử của L[n] thì X cũng là phần tử của
L[n+1].
e. Tương đương với :

P
1
= X là phần tử của L[1].
P
1
= X là phần tử đầu của L, hay
L = [X, … ] = [X|_] (a)
(P
n
→ P
n+1
) = (X là phần tử của L[n+1] :- X là phần
tử của L[n]).
= Nếu X là phần tử của L[n] thì X là phần tử của L[n]
thêm phần tử A ở đầu.
Prolog Fast Foot Prolog Fast Foot .

= Nếu X là phần tử của L[n] thì X là phần tử của
[A|L[n]].
= Nếu X là phần tử của L[n] thì X cũng là phần tử
của [_|L[n]].
= X là phần tử của [_|L[n]] if X là phần tử của L[n].
(b)
f. Chọn quan hệ : Ptử(Phàntử, Danhsách).
g. Chuyển thành vị từ của Prolog :
Domains
Phầntử = char (kiểu tùy ý)
Danhsách = char*
Predicates
Ptử(Phàntử, Danhsách)

Clauses
Ptử(X, [X | _ ]). (từ a)
Ptử(X, [_ | Y]) :- Ptử(X,Y). (từ b)
Thí dụ : Prefix.
(Danh sách đầu của một danh sách)
(Ap dụng truy chứng dạng thứ 1)
Danh sách X = 234 là danh sách đầu (prefix) của danh
sách L = 23457894566.
Nhưng danh sách Q = 457 không là danh sách đầu của
L.
33 34 N.T. Son
a. P = X là prefix của L.
b. P
n
= X[n] là prefix của L.
c. X[0] = [] là prefix của L.
Nếu X là prefix của L thì [A}X] là prefix của [A|L].
(truy chứng trên chiều dài của X).
[A|Y]) là prefix của [A|L] nếu Y là prefix của L.
d. Prefix([], L). (1)
Prefix([A|Y], [A|L]) :- Prefix(Y,L). (2)
Chú thích :
1. Ký hiệu [A|L] là thêm phần tử A vào đầu danh sách L.
2. Biến L trong (1) và (2) chẳng dính dánh gì với nhau.
Có thể viết lại (2) là
Prefix([A|Y], [A|Z]) :- Prefix(Y,Z).
3. Trường hợp này có 2 số nguyên để truy chứng là
chiều dài của X và chiều dài của L. Nhưng tính chất
prefix không thay đổi theo chiều dài của L nên ta
chọn truy chứng theo chiều dài của X. Một số thí dụ

sau có thể truy chứng trên nhiều số nguyên khác
nhau).
Thí dụ : Suffix.
(Danh sách đuôi của 1 danh sách)
(Ap dụng truy chứng dạng thứ 2)
Danh sách X = 566 là danh sách đuôi (suffix) của danh
sách L = 23457894566.
N.T. Son
Prolog Fast Foot Prolog Fast Foot .

Nhưng danh sách Q = 457 không là danh sách đuôi của
L.
a. P = X là suffix của L.
b. P
n
= X là suffix của L[n].
c. Danh sách X là phần đuôi của danh sách X.
Nếu Danh sách X là phần đuôi của danh sách L[n] thì X
là phần đuôi của danh sách L[n+1].
d. Subfix(L, L).
Subfix(X,[_|Z]) :- Subfix(X,Z).
Thí dụ : Sublist.
(Danh sách con của một danh sách)
(Ap dụng truy chứng dạng thứ 2)
Danh sách X = 579 là danh sách con của danh sách L =
234579894566.
Nhưng danh sách Q = 452 không là danh sách con của
L.
a. P = X là sublist của L.
b. P

n
= X là sublist của L[n].
c. Cắt chuỗi L làm 2 phần, L = PQ.
Chọn P = 234579 và Q = 894566.
Khi đó P là prefix của L.
Nếu X là suffix của P thì X là sublist của L.
d. Sublist(X,Y) :- Prefix(P,Y), Suffix(X,P).
35 36 N.T. Son
Chú thích :
1. Việc phân chia L thành P, Q với chủ ý lấy suffix của
một prefix. Nếu tồn tại một điểm cắt như vậy thì X là
chuỗi con của L. Việc kiểm tra điểm này có tồn tại
hay không do hệ thống Prolog lo, người lập trình
không phải lo.
2. Điểm cắt đôi chuỗi L[n] là tuỳ ý, do đó nó là dạng
truy chứng 2. Vì bài toán sẽ áp dụng cho chuỗi L[m]
với m < n. Nếu cắt tại phần tử đầu là truy chứng dạng
1, P = 2, Q = 34579894566.
3. Thử áp dụng dạng truy chứng 1 để giải bài tập này.
Thí dụ : Sublist.
(Ap dụng truy chứng dạng thứ 2)
a. P = X là sublist của L.
b. P
n
= X là sublist của L[n].
c. Cắt chuỗi L = 234579894566 làm 2 phần gồm P và Q.
Chọn P = 234 và Q = 579894566. Khi đó Q là suffix của
L. Nếu X là prefix của Q thì X là sublist của L. Việc
phân chia này với chủ ý lấy prefix của một suffix.
d. Sublist(X,Y) :- Prefix(X,Q), Suffix(Q,Y).

Thí dụ : Sublist.
(Ap dụng 2 lần truy chứng dạng 1)
a. P = X là sublist của L.
b. P
n
= X là sublist của L[n].
c. X là sublist của L[n].
N.T. Son
Prolog Fast Foot Prolog Fast Foot .

Nếu X là prefix của L thì X là sublist L.
(Trường hợp X không là prefix của L thì X có thể là
prefix của L’, với L’ là L bỏ phần tử đầu).
Nếu X là sublist của L thì X là sublist của [_|L].
d. Sublist(X,L) :- Prefix(X,L).
Sublist(X,[_|L]) :- Sublist(X,L).
Chú thích :
1. Khi trường hợp X không là prefix của L thì X có thể
là prefix của L nhưng bỏ đi phần tử đầu. Phần tử đầu
của L liên tiếp bị cắt đi nếu X chưa là prefix của L.
2. Như vậy có thể áp dụng tương tự cho suffix của L và
bỏ đi phần tử đuôi khi X không là suffix của L hay
không ?. Điều này không được vì không có cách trực
tiếp bỏ đi phần tử đuôi. Chỉ có cách xác định trực tiếp
phần tử đầu là nhờ biểu diễn head và tail).
3. Biến L của 2 mệnh đề trong phần d không dính dáng
gì với nhau.
Thí dụ : Kết nối 2 danh sách.
(Ap dụng truy chứng dạng thứ 1)
Danh sách X = 1234, danh sách L = 5678910. Danh sách

kết nối là XL = 12345678910.
a. P = Kết nối X vào L.
b. P
n
= Kết nối X[n] vào L.
37 38 N.T. Son
c. X[0] là danh sách trống thì kết quả là L.
X[1] là [H] thì kết quả là [H|L].
X[n+1] là [H|T] thì kết nối T với L sau đó lấy kết quả
thêm phần tử H ở đầu.
Chỉ cần thể hiện chiều dài 0 và chiều dài n+1.
Lấy vị từ append có 3 thông số. Thông số 1 là X, thông
số 2 là L và thông số 3 là kết quả.
d. Append([], L, L).
Append([H|T], L, [H|Z]) :- Append(T, L, Z).

Thí dụ : Sublist.
(Ap dụng truy chứng dạng thứ 2)
a. P = X là sublist của L.
b. P
n
= X là sublist của L[n].
c. Danh sách L có thể coi như gồm có 3 phần : P (prefix),
X và S (suffix).
Chuỗi L = PXS = 234579894566 thì P = 234, X = 579
và S = 894566.
Một chuỗi nào đó ( _ ) kết hợp với một chuỗi K (XS) có
kết quả là L và chuỗi K là kết quả của sự kết nối giữa X
và chuỗi nào đó.
Nếu có được sự kết nối như vậy thì X là chuỗi con của

L.
d. Sublist(X, PXS) :- Append(_ , XS, PXS),
Append(X, _ , XS).
N.T. Son
Prolog Fast Foot Prolog Fast Foot .
Chú thích :
1. Các thông số X, XS, PXS là tên của 3 biến, không
phải là kết nối. Tên biến được đặt như vậy để nhận
dạng sự kết hợp mong muốn giữa các danh sách. Do
đó có thể thay tên biến XS bằng tên Y và tên biến
PXS bằng tên L. Kết quả vẫn không có gì thay đổi.
Do đó có thể viết lại như sau :
Sublist(X,L) :-Append(_,K,L), Append(X,_,K).
2. Mệnh đề Append(_ , XS, PXS) được sử dụng ở dạng
này giống như để kiểm tra XS là suffix của PXS, còn
Append(X, _ , XS) giống như để kiểm tra X là prefix
của XS.
Thí dụ : Sublist.
(Ap dụng truy chứng dạng thứ 2)
a. P = X là sublist của L.
b. P
n
= X là sublist của L[n].
c. Subfix của prefix và sử dụng append.
Một chuỗi Q (PX) kết hợp với một chuỗi nào đó (_ ) có
kết quả là L (PXS) và chuỗi Q là kết quả của sự kết nối
giữa X và chuỗi nào đó.
Nếu có được sự kết nối như vậy thì X là chuỗi con của
L.
d. Sublist(X, PXS) :- Append(PX, _ , PXS),

Append(_ , X, PX).
Chú thích :
Vị từ Ptử có thể coi như là một trường hợp đặc biệt của
Sublist. Vì Ptử(X,Y) :- Sublist([X],Y).
Thí dụ : Đảo ngược một danh sách.
(Ap dụng truy chứng dạng thứ 1)
a. P = Đảo ngược danh sách L.
b. P
n
= Đảo ngược danh sách L[n].
c. L[0] có đảo ngược là L[0].
Để đảo ngược L[n+1] = [H|Y] ta đảo ngược Y sau đó kết
nối nó với H.
d. Reverse([], []).
Reverse([H|Y],Z) :- reverse(Y,T), append(T,[H],Z).
Thí dụ : Đảo ngược một danh sách.
a. P = Đảo ngược danh sách L.
b. P
n
= Đảo ngược danh sách L[n].
c. Nếu L[n] nghịch đảo thì L[n+1] có nghịch đảo. Lấy
phần tử đầu X của danh sách L append với danh sách
trống E, nghĩa là có [X|E]. Việc này thực hiện cho đến
khi L thành trống.
N.T. Son 39 40 N.T. Son
d. Reverse(L, Y) :- Reverse3(L, [], Y).
Reverse3([], E, E) :- !.
Reverse3([X | Z], E, Y) :- Reverse3(Z, [X|E], Y).
Prolog Fast Foot Prolog Fast Foot .
Chú thích : Tạo một vị từ trung gian Reverse3 có thêm một

thông số trung gian.
N.T. Son 41 42 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
TẠP LUẬN
• Trật tự của các rule trong phần clauses sẽ ảnh hưởng đến
thời gian thực thi.
• Các vị từ có thể đặt cùng tên với danh sách thông số khác
nhau.
Thí dụ :
Domains
Dssố = integer*
Dskýhiệu = symbol*
Dskýtự = char*
Predicates
Member(integer, Dssố)
Member(symbol, Dskýhiệu)
Member(char, Dskýtự)
Tùy theo dạng cụ thể của Member sẽ đồng nhất với dạng
thích hợp.
• Khi định nghĩa một vị từ nên để ý tính chất các thông số là
input (in) hay output (out).
Thí dụ :
Append([], X, X).
Append([X | T], Y, [X | Z]) :- Append(T, Y, Z).
Ta có ý định nghĩa Append với dạng (in, in, out) nhưng các
định nghĩa của ta vô tình cho cả trường hợp (out, int, int),
(in, out, in), (in, in, in).
Khi sử dụng trong trường hợp cụ thể nên xem xét các trạng
thài in, out của các thông số cho từng trường hợp.
• Một vị từ được gọi là Deterministic khi nó chỉ có một khả

năng lựa chọn. Ngược lại, nó được gọi là Non-
deterministic khi có nhiều khả năng lựa chọn.
Thí dụ :
Clauses
Làngười(socrates).
Chết(Ai) :- Làngười(Ai).
Vị từ Làngười và Chết là deterministic vì nó chỉ có một khả
năng lựa chọn.
Nhưng,
Clauses
Làngười(socrates). Làngười(platon).
Chết(Ai) :- Làngười(Ai).
Vị từ Làngười và Chết là non-deterministic vì có 2 khả
năng lựa chọn.
• Vị từ fail là vị từ chuẩn luôn có giá trị sai. Dùng fail với
mục đích tạo backtracking để vét cạn tất cả các khả năng
lựa chọn.
N.T. Son 43 44 N.T. Son
Prolog Fast Foot Prolog Fast Foot .
N.T. Son
Thí dụ :
Predicates
Nhàvăn(symbol, string)
In_ra
Clauses
Nhàvăn(nguyễnTuân, “ChiếcLưĐồngMắtCua”).
Nhàvăn(nguyễnDu, “Đoạn trường tân thanh”).
Nhàvăn(phạmthiênThư, “Đoạntrườngvôthanh”).
Nhàvăn(phạmThái, “Sơ kính tân trang”).
In_ra :- Nhàvăn(X,Y), write(X), write(Y), fail.

In_ra.
Clauses
In_ra.
Danh sách tất cả mệnh đề Nhàvăn(_,_) sẽ được in ra hết
nhờ vị từ fail.
• Vị từ cut (!) được dùng để ngăn chận backtracking. Khi
dòng thực hiện chương trình đi qua cut thì mọi mệnh đề
đứng trước nó đề trở thành deterministic.
Thí dụ :
Cl :- sb1, sb2, sb3, ….
Cl :- sb4, sb5, !, sb6, ….
Cl :- ….
Khi thực hiện tới sb6 thì không thể quay lại chọn các khả
năng còn lại của sb5, sb4, sb3, sb2, sb1, dù chúng còn
nhiều khả năng lựa chọn nữa. Ngoài ra mệnh đề Cl của
dòng thứ 3 ( sau ! ) cũng không được thử vì ! đã xóa các
khả năng lựa chọn còn lại của mệnh đề Cl. Vì coi như C1
của dòng thứ 1 và thứ 2 là đứng trước !, nên C1 của dòng
thứ 3 là khả năng lựa chọn còn lại của C1 cũng bị xóa.
Có hai lý do sử dụng cut :
1. Khi ý nghĩa của chương trình không muốn xem hết
các khả năng còn lại.
N.T. Son 45 46
2. Khi biết trước một số khả năng không bao giờ cho lời
giải có nghĩa.
Thí dụ :
Predicates
Hànhđộng(char)
Ktra(char)
Mụctiêu

Clauses
Hành động(‘1’) :- !, write(“In ra số 1”). (1)
Hành động(‘2’) :- !, write(“In ra số 2”). (2)
Hành động(‘3’) :- !, write(“In ra số 3”). (3)
Ktra(1). Ktra(2). Ktra(3).
Ktra(_) :- fail.
Mụctiêu :- readchar(N), Hànhđộng(N), Ktra(N).
Prolog Fast Foot Prolog Fast Foot .
N.T. Son 47 48 N.T. Son
Goal
Mụctiêu.
Nếu readchar nhận giá trị 1 thì Hànhđộng(1) thực hiện và
thực hiện lệnh write. Vì cut trước write nên subgoal
Hànhđộng được bỏ hết các khả năng còn lại. Do đó nếu
Ktra thất bại thì Mụctiêu thất bại.
Nếu readchar nhận giá trị 1 thì Hànhđộng(1) thực hiện và
thực hiện lệnh write. Và nếu không có cut trước write thì
subgoal Hànhđộng sẽ còn 2 khả năng lựa chọn. Do đó nếu
Ktra thất bại thì Hànhđộng(2) sẽ thực hiện và Ktra sẽ thực
hiện.
Cut của các mệnh đề sau cũng vậy.
Trong thí dụ trên Mụctiêu là non-deterministic hay
deterministic ?.
Goal Mụctiêu có 3 subgoal là :
readchar(N), Hànhđộng(N), Ktra(N).
Subgoal readchar(N) là deterministic.
Subgoal Hànhđộng(N) là deterministic vì các cut.
Nhưng Ktra(N) là non-deterministic.
Do đó Mụctiêu là non-deterministic.
Muốn nó trở thành deterministic thì thay :

Ktra(1). Ktra(2). Ktra(3).
bằng :
Ktra(1):-!. Ktra(2):-!. Ktra(3):-!.
Ktra(_) ;- fail.
• Tối ưu các vị từ được định nghĩa bằng đệ qui.
Khi một chương trình A gọi chương trình B thì phải lưu
tình trạng hiện hành của chương trình A để khi B hoàn tất
thì trở lại thi hành tiếp chương trình A.
Một tình trạng của chương trình được giữ trong stack
frame.
Nếu chương trình B là bước thi hành cuối cùng của chương
trình A thì không cần lưu lại trạng thái của A. Lúc này
quyền điều khiển sẽ đi đến nơi mà đến khi chương trình A
chấm dứt.
Một subgoal được gọi là bước cuối cùng nếu :
- Subgoal là subgoal cuối cùng của clause.
- Không có các điểm backtracking trong các subgoal
trước đó của clause.
Thí dụ :
Predicates
Giaithừa (real, real)
Clauses
Giaithừa(1, 1).
Giaithừa(N,T) :- M=N–1, Giaithừa(M,S), T=S*N.
Subgoal Giaithừa(M,S) không phải là bước cuối cùng vì
sau nó còn subgoal T = S*N.
Prolog Fast Foot Prolog Fast Foot .
Thí dụ :
Predicates
Đếm(integer)

Clauses
Đếm(N) :- N > 100.
Đếm(N) :- write(N), nl, M = N+1, Đếm(M), nl.
Subgoal Đếm(M) không phải là bước cuối cùng vì sau nó
còn subgoal nl.
Thí dụ :
Clauses
Đếm(N) :- N > 100.
Đếm(N) :- write(N), M=N+1, Kiểm(M), Đếm(M).
Kiểm(X) :- X >= 0.
Kiểm(X) :- X <0.
Subgoal Đếm(M) không phải là bước cuối cùng vì có
backtracking trước nó là Kiểm(M).
Thí dụ :
Predicates
Repeat
Clauses
Repeat.
Repeat :- Repeat.
Subgoal Repeat là bước cuối cùng.
• Ngôn ngữ khai báo (declarative language) so với ngôn ngữ
cấu trúc (structured language).
Thí dụ :
Cho ma trận 4x4, mỗi ô có một giá trị từ 1 đến 16. Các ô
khoanh tròn là các bước đi bị cấm.
Cho một điểm bắt đầu start và điểm cuối goal như hình vẽ.
Tìm đường đi từ start đến goal.
16 15
goal
14 13

12

11 10 9
8

7 6 5
1 2 3 start 4
Một con đường là : 3→6→7→8→12→16→15.
Chương trình được viết bằng Pascal
Program MazeSearch;
Type
Đường_arr = array[1 … 6, 1 … 2] of integer;
Const
max = 6;
Đường : Đường_arr = ((3,6), (6,7), (7,8), (8,12), (12,16),
(16,15));
Var
goal, start : integer;
Procedure Tìm (start, goal : integer);
Var
N.T. Son 49 50 N.T. Son

×