0

[Series Prolog] - Chương 1: Sự kiện, luật và truy vấn

Bài trước: Giới thiệu

1.1. Vài ví dụ đơn giản

Trong Prolog có ba cấu trúc cơ bản là sự kiện (hay dữ kiện) (fact), luật (hay quy tắc) (rule) và truy vấn (query).
Một tập hợp các sự kiện và các luật được gọi là một cơ sở tri thức (knowledge base) hay cơ sở dữ liệu (database) và lập trình trong Prolog hoàn toàn chỉ là việc viết các cơ sở tri thức. Nghĩa là, một chương trình trong Prolog đơn giản là các cơ sở tri thức.
Để sử dụng một chương trình Prolog, chúng ta chỉ cần đặt ra các truy vấn (query) về các thông tin được lưu trong cơ sở tri thức.

Sau đây sẽ là một số ví dụ đơn giản để bước đầu làm quen với Prolog.

Ví dụ 1

Mở một text editor và tạo một file có đuôi .pl để lưu cơ sở tri thức sau (ta gọi nó là KB1):

woman(mia). 
woman(jody). 
woman(yolanda). 
playsGuitar(jody). 
party.

KB1 đơn giản chỉ là các sự kiện. Ở đây, chúng ta có năm sự kiện cung cấp cho chúng ta một số thông tin: Mia, Jody và Yolanda là những người phụ nữ, Jody chơi guitar và có một party. Chú ý rằng, các tên riêng như Mia, Jody hay các thuộc tính như woman hay mệnh đề party khi được đưa vào cơ sở tri thức phải có chữ cái đầu là chữ thường (chúng ta sẽ nói tới điều này ở phần cú pháp).
Bây giờ chúng ta sẽ thực hiện một vài truy vấn. Giả sử ta muốn hỏi Mia có phải là một người phụ nữ hay không, ta đưa ra truy vấn (chú ý dấu chấm và không cần gõ ?- vì đó là dấu nhắc của Prolog):

?- woman(mia).

Khi đó, Prolog sẽ trả lời là true vì rõ ràng đây là một trong số các sự kiện có trong KB1.
Tương tự, ta có thể đưa ra truy vấn:

?- playsGuitar(jody).

và Prolog trả lời true. Tuy nhiên nếu ta đưa ra truy vấn:

?- playsGuitar(mia).

thì Prolog sẽ trả lời false.
Điều này là do đây là sự kiện không xuất hiện trong KB1, hơn nữa trong KB1 không có thêm thông tin hữu ích nào (đó là các luật) để Prolog có thể suy luận tiếp. Do đó Prolog kết luận sự kiện playsGuitar(mia) không thể suy ra được từ KB1.
Sau đây là hai ví dụ quan trọng khác. Giả sử ta đặt ra truy vấn:

?- playsGuitar(vincent).

Khi đó, Prolog sẽ trả lời false.
Điều này là do truy vấn này đề cập đến một người (là Vincent) không có thông tin nào trong KB1. Nên Prolog kết luận playsGuitar(vincent) không thể suy diễn từ KB1.
Hãy thử đặt ra truy vấn sau:

?- tatooed(jody).

Khi đó, Prolog sẽ báo lỗi vì thuộc tính tatooed chưa được định nghĩa trong KB1.
Chúng ta cũng có thể đưa ra các truy vấn khác, chẳng hạn như:

?- party.

và Prolog sẽ trả lời true.
Nếu ta đặt ra truy vấn:

?- rockConcert.

thì Prolog sẽ báo lỗi vì mệnh đề này chưa được định nghĩa trong KB1.

Ví dụ 2

Bây giờ chúng ta sẽ đi đến một ví dụ về cơ sở tri thức có chứa các luật. Ta gọi cơ sở tri thức này là KB2:

happy(yolanda). 
listens2Music(mia). 
listens2Music(yolanda) :- happy(yolanda). 
playsGuitar(mia) :- listens2Music(mia). 
playsGuitar(yolanda) :- listens2Music(yolanda). 

Trong KB2 có hai sự kiện và ba luật. Kí hiệu :- đọc là "nếu", ví dụ luật listen2Music(yolanda) :- happy(yolanda) có nghĩa là "Yolanda nghe nhạc nếu như Yolanda vui". Phần bên trái của :- được gọi là head (phần đầu) và phần bên phải được gọi body (phần thân) của luật. Như vậy một luật có dạng head :- body, có nghĩa là nếu body đúng thì head cũng đúng.
Khi một cơ sở tri thức có chứa một luật head :- body, và trong cơ sở tri thức có chứa body hoặc body có thể được suy diễn từ cơ sở tri thức, khi đó Prolog suy ra được head.
Bây giờ hãy thử đặt ra một vài truy vấn. Giả sử ta muốn hỏi Mia có chơi guitar hay không:

?- playsGuitar(mia).

Khi đó Prolog sẽ trả lời true. Ta thấy mặc dù sự kiện playsGuitar(mia) không xuất hiện trong KB2 nhưng Prolog tìm thấy một luật có chứa sự kiện này là playsGuitar(mia) :- listen2Music(mia)listen2Music(mia) là một sự kiện xuất hiện trong KB2.
Một ví dụ khác, xem xét truy vấn sau:

?- playsGuitar(yolanda).

Prolog cũng trả lời true. Bằng cách sử dụng sự kiện happy(yolanda) và luật listen2Music(yolanda) :- happy(yolanda), Prolog suy ra được sự kiện listen2Music(yolanda). Sử dụng sự kiện này và luật playsGuitar(yolanda) :- listen2Music(yolanda), Prolog suy luận ra sự kiện playsGuitar(yolanda).
Như vậy, một sự kiện được sinh ra bằng một phép suy diễn từ một luật nào đó trong cơ sở tri thức có thể được dùng như là sự kiện đầu vào cho các luật khác.

Các sự kiện và các luật nằm trong cơ sở tri thức còn được gọi chung là các mệnh đề (clause). Do đó ta nói KB2 có chứa năm mệnh đề, trong đó có hai sự kiện và ba luật, hay KB1 cũng có năm mệnh đề nhưng trong đó có bốn sự kiện.

Ta cũng nói rằng, KB2 có chứa ba vị từ (predicate) hay thủ tục (procedure), đó là: listen2Music, happy, playsGuitar.
Vị từ happy được định nghĩa bằng cách dùng mệnh đề đơn (sự kiện).
Vị từ listen2MusicplaysGuitar được định nghĩa bằng cách dùng hai mệnh đề: listen2Music được định nghĩa bằng cách dùng một sự kiện và một luật, còn playsGuitar được định nghĩa bằng hai luật.

Một chú ý cuối cùng là: ta có thể xem một sự kiện như là một luật với body là rỗng.

Ví dụ 3

Cơ sở tri thức KB3 của chúng ta sẽ có năm mệnh đề, trong đó có hai sự kiện và ba luật:

happy(vincent). 
listens2Music(butch). 
playsGuitar(vincent) :- 
         listens2Music(vincent), 
         happy(vincent). 
playsGuitar(butch) :- 
         happy(butch). 
playsGuitar(butch) :- 
      listens2Music(butch).

KB3 định nghĩa ba vị từ giống như KB2 theo cách khác. Cụ thể, ta chú ý rằng, luật:

playsGuitar(vincent) :- 
         listens2Music(vincent), 
         happy(vincent). 

có hai phần tử trong phần body. Hai phần tử này có một cách gọi khác là mục tiêu (goal). Dấu phẩy , ở đây có vai trò như toán tử AND, nghĩa là để có được sự kiện playsGuitar(vincent), ta phải có đủ hai sự kiện là listen2Music(vincent)happy(vincent).
Do đó nếu ta đặt ra truy vấn sau đây:

?- playsGuitar(vincent).

thì Prolog sẽ trả lời false, bởi vì KB3 chỉ có chứa happy(vincent) mà không chứa và cũng không thể suy ra được listen2Music(vincent).
Ta cũng chú ý rằng, KB3 có chứa hai luật có cùng head:

playsGuitar(butch) :- 
         happy(butch). 
playsGuitar(butch) :- 
      listens2Music(butch). 

Điều này có nghĩa là để có được sự kiện playsGuitar(butch) thì chỉ cần có một trong hai sự kiện là happy(butch) hoặc listen2Music(butch).
Do đó, nếu ta đưa ra truy vấn:

?- playsGuitar(butch).

thì Prolog sẽ trả lời là true, bởi vì mặc dù KB3 không có sự kiện happy(butch) nhưng lại có sự kiện playsGuitar(butch).
Ta cũng có một cách khác để viết lại luật playsGuitar(butch) như sau:

playsGuitar(butch) :- happy(butch); 
						listen2Music(butch).

Dấu ; ở đây có vai trò như toán tử OR.

Ví dụ 4

Bây giờ chúng ta đi tiếp thêm một ví dụ nữa. Cơ sở tri thức KB4 của chúng ta như sau:

woman(mia). 
woman(jody). 
woman(yolanda). 

loves(vincent,mia). 
loves(marsellus,mia). 
loves(pumpkin,honey_bunny). 
loves(honey_bunny,pumpkin).

Trong KB4, ta thấy một vị từ có hai đối số là loves biểu diễn một mối quan hệ.
Trong ví dụ này, chúng ta sẽ làm quen với các truy vấn có chứa biến. Ví dụ:

?- woman(X).

Ở đây, X là một biến dùng để lưu thông tin. Câu truy vấn trên có nghĩa là: "hãy cho biết trong những người đã biết, những ai là phụ nữ". Khi đó, Prolog sẽ tìm kiếm trong KB4 từ đầu đến cuối và đồng nhất (hay so khớp) biểu thức woman(X) với các thông tin có chứa trong KB4. Phần tử đầu tiên trong KB4 là woman(mia) nên Prolog đồng nhất X với mia để mục tiêu trong truy vấn được thỏa mãn và Prolog sẽ thông báo lại cho chúng ta như sau:

X = mia

Ta thấy trong KB4, không chỉ có Mia là phụ nữ mà còn có Jody và Yolanda. Chúng ta có thể nhận được thêm các thông tin này bằng cách gõ ;:

X = mia ;

Như đã biết, dấu ; có nghĩa là "hoặc", nên truy vấn trên có nghĩa là: "còn ai là phụ nữ nữa không ?". Prolog sẽ tiếp tục tìm kiếm trong KB4 nhưng bắt đầu ở phần tử thứ hai và đồng nhất X với jody:

X = mia ;
X = jody

Nhấn ; thêm một lần nữa, chúng ta sẽ có thêm kết quả:

X = mia ;
X = jody ;
X = yolanda.

yolanda là kết quả cuối cùng mà Prolog có thể tìm được, vì Prolog không thể đồng nhất thêm được nữa với vị từ woman vì phần còn lại của KB4 không chứa vị từ này.
Bây giờ chúng ta thực hiện một truy vấn phức tạp hơn một chút:

?- loves(marsellus, X), woman(X).

Chú ý rằng, dấu , có nghĩa là "và", nên truy vấn trên có nghĩa là: "tìm một người X sao cho marsellus yêu X và X là phụ nữ". Ta thấy trong KB4 có hai sự kiện là woman(mia)loves(marsellus,mia). Prolog đồng nhất X với mia để hai mục tiêu trong truy vấn trên đều được thỏa mãn. Khi đó, Prolog thông báo:

X = mia.

Chúng ta sẽ nói kĩ hơn về phép đồng nhất trong Prolog ở chương sau.

Ví dụ 5

Ví dụ cuối cùng này sẽ giới thiệu sơ lược qua dùng các biến trong cơ sở tri thức. Cơ sở tri thức KB5 của chúng ta như sau:

loves(vincent,mia). 
loves(marsellus,mia). 
loves(pumpkin,honey_bunny). 
loves(honey_bunny,pumpkin). 
    
jealous(X,Y):-  loves(X,Z),  loves(Y,Z).

Chú ý đến cách viết luật của chúng ta trong ví dụ này, đó là có chứa ba biến X,YZ. Luật này nói rằng "X ghen với Y nếu tồn tại Z nào đó sao cho X yêu Z và Y cũng yêu Z". Không giống như các cơ sở tri thức ở các ví dụ trước, luật trong KB5 có tính tổng quát. Bây giờ hãy thử đặt truy vấn sau:

?- jealous(marsellus,W).

Truy vấn trên có nghĩa là "Marsellus có thể ghen với ai ?". Ta thấy Vincent là một trong số đó vì cả hai cùng yêu Mia, nên Prolog sẽ trả lời:

W = vincent

Nếu thử nhấn ; thì chúng ta sẽ thấy thêm một kết quả khá vô lý:

W = vincent ;
W = marsellus.

Tuy nhiên nó vẫn đúng luật như đã nêu trong KB5.
Hãy thử đặt tiếp truy vấn sau:

?- jealous(X,Y).

và xem kết quả (truy vấn trên có nghĩa là gì?).

1.2. Cú pháp

Qua phần ví dụ, chúng ta đã gặp các loại biểu thức chẳng hạn như jody, playsGuitar(mia) hay X. Chúng được gọi chung là các hạng tử (term) và trong Prolog có bốn loại hạng tử: atom, số, biếnhạng tử phức hợp (hay cấu trúc). Các atom và số được gộp chung thành các hằng. Các hằng và các biến tạo thành các hạng tử đơn trong Prolog.

Bây giờ chúng ta nói qua về các kí tự cơ bản được sử dụng trong Prolog. Đó là các chữ cái hoa A, B,..., Z; các chữ cái thường a, b,..., z; các chữ số 1, 2,..., 9. Ngoài ra còn có dấu gạch dưới (_) và một vài kí tự đặc biệt chẳng hạn như +, -, *, /, <, >, =, :, ., &, ~. Khoảng trắng cũng là một kí tự.
Một chuỗi là một dãy liên tục các kí tự.

Kiểu "atom"

Một atom có thể là:

  1. Một chuỗi các kí tự được tạo thành từ các chữ hoa, chữ thường, chữ số và dấu gạch dưới và phải bắt đầu bằng một chữ thường. Ví dụ mia, listen2Music, playsGuitar, element_at.
  2. Một dãy tùy ý các kí tự được bao bọc trong cặp dấu nháy đơn. Ví dụ ' ', 'Vincent', 'The Door' 'Five_Dollar', '&%^@$#!'. Một dãy các kí tự nằm giữa cặp dấu nháy đơn được gọi là tên của atom.
  3. Một chuỗi các kí tự đặc biệt. Ví dụ @=, @===>, :-,, hay ;. Ta thấy :-, ; hay , là các atom có ý nghĩa xác định.

Kiểu số

Trong phạm vi của Series Prolog này, ta chỉ đề cập đến các số nguyên mà không đề cập đến các số thực vì số thực ít khi được sử dụng trong Prolog.
Các số nguyên được sử dụng nhiều trong Prolog và có công dụng riêng của nó mà chúng ta sẽ thảo luận ở Chương 5.
Cú pháp của nó rất đơn giản và quen thuộc: 365, -1000, 0, 1,...

Biến

Một biến là một chuỗi các chữ hoa, chữ thường, chữ số, dấu gạch dưới và bắt đầu bằng một chữ hoa hoặc dấu gạch dưới. Ví dụ X, Y, _tag, List, _input, Output.
Biến _ (chỉ có một dấu gạch dưới) được gọi là biến vô danh hay nặc danh.

Hạng tử phức hợp

Các atom, số và biến là các thành phần cơ bản để xây dựng nên các hạng tử phức hợp.
Các hạng tử phức hợp được xây dựng bởi một hàm tử (functor) và một dãy các đối của nó (argument). Các đối được đặt giữa cặp ngoặc tròn, tách nhau bởi dấu phẩy và được đặt sau hàm tử. Vậy một hạng tử phức hợp có dạng functor(arg1, arg2,..., argn). Chú ý là giữa hàm tử và dấu ngoặc tròn không được có khoảng trắng và hàm tử phải là một atom. Các đối có thể là bất kì hạng tử nào.
Ở các ví dụ trước, chúng ta đã thấy một vài hạng tử phức hợp. Ví dụ playsGuitar(jody) là một hạng tử phức hợp: playsGuitar là hàm tử của nó và jody là đối của nó. Ví dụ khác là loves(vincent,mia) hay jealous(marsellus,W) là hạng tử phức hợp có chứa một biến.

Ta cũng có thể lồng các hạng tử phức tử phức hợp lại với nhau bao nhiêu lần tùy ý, chẳng hạn như hide(X, father(father(butch))) cũng là một hạng tử phức hợp. Nó có hàm tử là hide, đối thứ nhất của nó là biến X và đối thứ hai là một hạng tử phức hợp khác là father(father(butch)). Cấu trúc này thường được sử dụng trong Prolog, đó là đệ quy.

Số lượng các đối của một hạng tử phức hợp được gọi arity. Ví dụ hạng tử woman(mia) có arity là 1 và hạng tử loves(vincent,mia) có arity là 2.
Arity khá quan trọng trong Prolog. Prolog cho phép chúng ta định nghĩa hai vị từ có cùng hàm tử nhưng khác số lượng các đối. Chúng ta sẽ nói kĩ tới phần này ở những chương sau.
Thông thường, khi nói đến các vị từ, chúng ta thường dùng kèm với hậu tố /arity.
Ví dụ, trong KB2 có định nghĩa ba vị từ listen2Music/1, happy/1, playsGuitar/1. Điều này giúp chúng ta phân biệt được các vị từ có cùng tên nhưng có số đối khác nhau.

Như vậy là chúng ta đã bước đầu làm quen với Prolog thông qua vài ví dụ đơn giản. Ở các chương sau, chúng ta sẽ đi vào các khái niệm nền tảng của Prolog.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí