Sinh viên cần nắm được các nội dung sau:
• Môi trường làm việc của PROLOG
• Cách định nghĩa vấn đề trong PROLOG: vị từ
• Cách biểu diễn vấn đề trong PROLOG: các sự kiện, luật
• Các chương trình ví dụ
• Cách đặt câu hỏi và nhận câu trả lời trong PROLOG
• Phân biệt Goal nội và goal ngoại
24 trang |
Chia sẻ: Kiên Trung | Ngày: 13/01/2024 | Lượt xem: 852 | Lượt tải: 0
Bạn đang xem trước 20 trang nội dung tài liệu Đề cương môn học Thực hành ngôn ngữ lập trình, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
thay đổi cách trả lời true_false “khó chịu” của prompter và loại bỏ sự cần
thiết phải có 2 bản sao của đoạn mã như đã hiện thực bằng cách tạo ra một lớp
mới cho ứng dụng Prioritizer và xóa đoạn mã cũ không còn cần thiết.
4.10. Thay đổi Prompter
Chúng ta đã sử dụng một thực thể của lớp Prompter để tạo tất cả các
thành phần giao tiếp với người sử dụng trong ứng dụng của chúng ta. Vấn để ở
đây là một thực thể prompter chỉ làm được một việc mà thôi đó là: đưa yêu
cầu cho người và nhận đáp ứng từ người sử dụng(hay là sử dụng đáp ứng mặc
định) trong khi bây giờ điều chúng ta muốn ở đây lại là cho phép người sử
dụng click vào từ “yes” hay “no” để cung cấp các đáp ứng của họ.
Tuy các prompter chỉ cho phép người sử dụng gõ vào các đáp ứng
nhưng chúng ta cũng có một thành phần giao diện khác cho phép người sử
dụng đáp ứng bằng cách click vào các lựa chọn và đối tượng này dĩ nhiên là
pop-up menu, thuộc vào lớp Menu. Do vậy, đây sẽ là nơi chúng ta sẽ làm việc
để đạt được yêu cầu về việc thay đổi cách đáp ứng của người sử dụng.
Chúng ta sẽ làm tương tự với các vấn đề về việc yêu cầu người sử
dụng sắp xếp các danh sách các lựa chọn.
Chúng ta sẽ tạo một phương thức mới có tên là confirm: cho lớp Menu
để có một menu pop up có hai lựa chọn: yes và no. Phương thức này có đối số
là câu hỏi mà chúng ta sẽ đưa cho người sử dụng. Chú ý là chúng ta không nên
mã cố định câu hỏi này vì chúng ta muốn tổng quát hóa phương thức này.(Đây
cũng chính là một mục tiêu quan trọng trong việc thiết kế hướng đối tượng).
Mở CHB, chọn lớp Menu, nhấn nút Class rồi chọn new method từ pane
menu và gõ đoạn mã sau vào:
confirm: queryString
“Return Boolean true for Yes, false for No.”
| labelTmp tempMenu respone |
labelTmp := menuString, ‘\Yes\No’.
tempMenu := Menu
labels: labelTmp withCrs
lines: #(1)
selectors: (Array with: true with: true with: false).
^tempMenu popUpAt: Cursor offset.
Ở dòng 4 của phương thức này, chúng ta nối câu hỏi được truyền thông
qua tham số khi phương thức được gọi với các nhãn “Yes” và “No” để tạo nên
nội dung của menu pop-up. Do người sử dụng cũng có thể chọn vào câu hỏi
(điều này ít khi xảy ra) nên chúng ta cũng phải cung cấp giá trị cho nó ở trong
phần selector. Các dấu backslashes(\) trong phần tham số labels: dùng để ngăn
cách giữa các thành phần trong menu và được chuyển thành dấu xuống
dòng(carriage return) sau khi chúng ta gửi đến chuỗi này thông điệp withCrs.
Thông số labels: cung cấp một chuỗi mà trong đó tất cả các dấu \ đều
được chuyển thành dấu xuống dòng và ở dòng kế tiếp chúng ta sẽ đặt một
đường thẳng ngăn cách sau dòng 1 để ngăn cách giữa chọn lựa Yes và No.
Tham số selectors: trả về giá trị true tương ứng khi người sử dụng click vào
câu hỏi hay câu trả lời đầu tiên(Yes) và false nếu người sử dụng chọn No. Chú
ý rằng chúng ta phải đặt kiểu tường minh của tham số selectors: là kiểu array
vì nếu không thì phương thức này sẽ không trả về một giá trị kiểu Boolean mà
trả về các ký hiệu #true và #false. Khi đó, hiển nhiên sortBlock sẽ không thể
hiểu được các ký hiệu này và gây ra lỗi.
Dòng cuối cùng của đoạn mã trên dùng để báo cho thực thể tempMenu
của lớp Menu biết vị trí đặt menu pop up là tại vị trí hiện tại của con trỏ. Dấu ^
dùng để trả về giá trị của phương thức.
Bây giờ chúng ta sẽ thay đổi phương thức prioritize một ít để có thể sử
dụng được phần giao diện người dùng mới này. Chọn phương thức prioritize
trong lớp DemoClass từ CHB và thay đổi dòng mã dùng để gán danh sách đã
sắp xếp vào biết result như sau:
result := SortedCollection sortBlock:
[ :a :b| Menu confirm: ‘Does ’, a printString,
‘ have a higher priority than ‘,
b printString, ‘ ?’
].
Tất cả các dòng mã khác trong method này đều không có gì thay đổi.
Save phương thức này lại và làm tương tự với phương thức prioritize trong lớp
ScreenDispatcher. Bây giờ chúng ta có thể kiểm tra thử các phương thức này.
Chúng ta sẽ thấy có một pop up menu hiển thị lên đê yêu cầu người sử dụng
sắp xếp danh sách các lựa chọn. Người sử dụng lúc này chỉ cần click chuột
vào câu trả lời mà họ muốn. Nếu người sử dụng, vì một lý do nào đó click
chuột vào câu hỏi thì chúng ta cũng nhận được câu trả lời đã được đặt mặc
định là “Yes” (chúng ta hoàn toàn có thể thay đổi giá trị này thành “No” hay
thậm chí có thể có một phương thức để giải quyết vấn đề này bằng cách thay
đổi giá trị của phần tử đầu tiên trong dãy của tham số selectors:)
4.11. Hợp nhất mã(Consolidating the code)
Trước đây, trong quá trình xây dựng ứng dụng Prioritize để cho đơn
giản, chúng ta đã dùng 2 phiên bản giống nhau để tạo hai phương thức trong
hai lớp khác nhau. Nhưng nếu vẫn để như vậy thì ứng dụng của chúng ta sẽ
thiếu tính nhất quán. Do đó, chúng ta sẽ tạo ra một lớp mới chứa phương thức
này để giải quyết vấn đề dư thừa mã này và sau đó gọi nó từ lớp DemoClass
và ScreenDispatcher.
Đầu tiên chép phần đoạn mã của phương thức prioritizer vào trong
clipboard bằng cách mở cửa sổ CHB, chọn phương thức này trong lớp
DemoClass hoặc lớp ScreenDispatcher. Sau đó, chọn lớp tổng quát nhất (lớp
Object) rồi chọn add subclass từ pane menu.
Chúng ta sẽ thấy hệ thống yêu cầu cung cấp tên cho lớp con của lớp
Object mới này. Chúng ta nhập vào tên lớp này là “Prioritizer”và nhấn enter.
Sau đó, chúng ta sẽ nhìn thấy một menu pop up có vẻ khó hiểu yêu cầu chúng
ta chọn kiểu lớp con mà chúng ta sẽ tạo. Đừng quan tâm đến ý nghĩa của
chúng lúc này, cứ chọn “subclass” option. Tiếp theo, không cần thay đổi gì
trong đoạn mô tả lớp và do CHB đã tự động chọn lớp mới này nên chúng ta cứ
chọn new method từ ô danh sách các method còn trống ở góc phải trên. Một
mẫu (template) của một method mới sẽ xuất hiện trong khung soạn thảo
(editing pane). Chọn tất cả đoạn text này rồi chọn paste trong pane menu.(chú
ý không nhấn vào phím backspace trong lúc này nếu không dữ liệu trong
clipboard sẽ bị xóa).
Để thống nhất với các qui tắc của Smalltalk/V chúng ta sẽ đổi tên
method của chúng ta thành run để nghe có vẻ như nó sẽ thực sự thực hiện
những gì mà chúng ta yêu cầu từ các lớp gọi nó.
Chọn tên phương thức prioritize và đổi lại thành run.
Chọn save từ pane menu.
Bây giờ, chúng ta có thể sửa 2 phương thức prioritize trong lớp
DemoClass và ScreenDispatcher để gọi phương thức vừa được tạo ở trên. Hai
phương thức này sẽ được thay đổi một cách tương tự nhau.
Chọn phương thức prioritize của một trong hai lớp trên từ CHB rồi xóa
toàn bộ phần đoạn mã của nó(có thể xóa luôn các comments). Sau đó, gõ dòng
mã sau vào:
Prioritizer new run.
Dòng mã này dùng để tạo ra một thực thể mới của lớp Prioritizer và
thực thi phương thức run mà chúng ta vừa định nghĩa ở trên.
(Tất cả các lớp đều biết cách tự tạo ra các thực thể mới nên chúng ta
không cần phải định nghĩa phương thức new trừ khi chúng ta muốn làm gì
khác ngoài những gì được thừa kế từ hành vi new)
Do chúng ta không thay đổi gì đối với các menu trong lớp DemoClass
và lớp ScreenDispatcher nên chúng ta vẫn có thể gọi ứng dụng Prioritizer từ
chúng theo cách tương tự như trước đây.
4.12.
Tài liệu tham khảo:
1/ Smalltalk/V Tutorial
2/ Dan Shafer and Dean A.Ritz Practical Smalltalk Using smalltalk/V
3/ Henri E.Bal Dick Grune Programming language Essentials
PHẦN III: LISP
Tiết 11: Giới thiệu ngôn ngữ LISP
Tiết 12: Thao tác trên ký hiệu(Symbol Manipulation), các thành phần cơ bản của
LISP
Sinh viên cần nắm được các nội dung sau:
• Hiểu được các thao tác trên ký hiệu của Lisp (Symbol Manipulation)
• Tại sao lại chọn Lisp để thao tác trên các ký hiệu
• Các kiểu dữ liệu cơ bản và các symbol_manipulation primitive trong Lisp
• Môi trường làm việc của GCLISP
• Cách soạn thảo và load chương trình
Bài tập / bài thực hành:
1/Tính các biểu thức sau trong CLISP
a/(+ 3.14 2.71)
b/(+ (* 2 2) (/ 2 2))
c/(/ (+ 3 1) (- 3 1))
d/(* (MAX 3 4 5) (MIN 3 4 5))
e/(MIN (MAX 3 1 4) (MAX 2 7 1))
2/Trong các đối tượng sau đối tượng nào thuộc loại atom, list hoặc không thuộc loại
nào trong hai loại này
ATOM
(THIS IS AN ATOM)
(THIS IS AN EXPRESSION)
((A B) (C D)) 3 (3)
(LIST 3)
(/ (+ 3 1) (- 3 1))
)(
((()))
(()())
((())
())(
((ABC
3/Xác định giá trị của các dạng(form) sau:
(first `(p h w))
(rest `(b k v n))
(first `((a b) (c d)))
(first (rest ‘((a b) (c d))))
(rest (first ‘((a b) (c d))))
(rest (first (rest ‘((a b) (c d)))))
(first (rest (first ‘((a b) (c d)))))
4/Xác định giá trị của các form sau:
(first (rest (first (rest ‘((a b) (c d) (e f))))))
(first (first (rest (rest ‘((a b) (c d) (e f))))))
(first (first (rest ‘(rest ((a b) (c d) (e f))))))
(first (first ‘(rest (rest ((a b) (c d) (e f))))))
(first ‘(first (rest (rest ((a b) (c d) (e f))))))
‘(first (first (rest (rest ((a b) (c d) (e f))))))
5/Chỉ sử dụng các primitives FIRST và REST để chọn ra symbol PEAR từ các biểu
thức sau:
(apple orange pear grapefruit)
((apple orange) (pear grapefruit))
(((apple) (orange) (pear) (grapefruit)))
(apple (orange) ((pear)) (((grapefruit))))
((((apple))) ((orange)) (pear) grapefruit)
((((apple) orange) pear) grapefruit)
6/Xác định giá trị của các dạng sau
(append ‘(a b c) ‘( ))
(list ‘(a b c) ‘( ))
(cons ‘(a b c) ‘( ))
7/Xác định giá trị của các dạng(form) sau theo đúng thứ tự được cho
(setf tools (list ‘hammer ‘screwdriver))
(cons ‘pliers tools)
tools
(setf tools (cons ‘pliers tools))
tools
(append ‘(saw wrench) tools)
tools
(setf tools (append ‘(saw wrench) tools))
8/Xác định giá trị của dạng sau
(cons (first nil) (rest nil))
9/
(length ‘(plato socrates aristotle))
(length ‘((plato) (socrates) (aristotle)))
(length ‘((plato socrates aristotle)))
(reverse ‘(plato socrates aristotle))
(reverse ‘((plato) (socrates) (aristotle)))
(reverse ‘((plato socrates aristotle)))
10/
(length ‘((car chevrolet) (drink coke) (cereal wheaties)))
(reverse ‘((car chevrolet) (drink coke) (cereal wheaties)))
(append ‘((car chevrolet) (drink coke))
(reverse ‘((car chevrolet) (drink coke))))
Tiết 13: Thủ tục, các thành phần cơ bản khác: Predicates và Conditionals và sự đệ qui
Sinh viên cần nắm được các nội dung sau:
• Cách định nghĩa các procedure
• Nắm được các thuật ngữ: variable, body, lexical variable, và special variable.
• Hai kỹ thuật để định nghĩa thủ tục: progressive envelopment và comment
translation
• Sự đệ qui thủ tục
• Sự trừu tượng thủ tục (procedure abstraction)
Bài tập / bài thực hành:
1/ Định nghĩa thủ tục Exchange nghịch đảo các giá trị trong một danh sách hai phần
tử
Ví dụ:
* (setf sinners ‘(adam eve))
* (exchange sinners)
(EVE ADAM)
2/Định nghĩa thủ tục CONSTRUCT để làm công việc giống như hàm CONS
3/Định nghĩa thủ tục ROTATE-LEFT để chuyển(quay) phần tử đầu tiên của danh
sách nhập vào (là tham số của hàm) về cuối.
Ví dụ:
* (rotate_left ‘(a b c))
(B C A)
* (rotate_left (rotate_left ‘(a b c)))
(C A B)
4/Định nghĩa thủ tục ROTATE_RIGHT tương tự như ROTATE_LEFT nhưng theo
chiều ngược lại (dùng BUTLAST)
5/Định nghĩa thủ tục PALINDROMIZE có tham số là một danh sách và trả về 1 danh
sách có tính đối xứng từ danh sách này(có độ dài gấp đôi danh sách đưa vào).
Ví dụ:
*(palindromize ‘( a b c ))
(A B C C B A)
6/Định nghĩa các thủ tục chuyển đổi giữa hai loại nhiệt độ: F-to-C và C-to-F theo
công thức dưới đây
C = (F + 40) x 5/9 - 40
F = (C + 40) x 9/5 - 40
Ví dụ:
* (f-to-c 32)
0
* (f-to-c 98.6)
37.0
* (f-to-c 212)
100
7/Định nghĩa vị từ DIVISIBLE_BY_THREE đê xác định xem một số nguyên có chia
hết cho 3 được không. Dùng primitive REM nhận vào tham số là hai số nguyên và trả
về phần dư của phép chia giữa chúng.
Ví dụ:
* (divisible-by-three 6)
T
* (divisible-by-three 7)
NIL
* (divisible-by-three 8)
NIL
8/Định nghĩa vị từ PALINDROMEP để kiểm tra xem danh sách đưa vào có đối xứng
không.
Ví dụ:
* (palindromep ‘(a b c b a))
T
* (palindromep ‘(a b c c b a))
T
* (palindromep ‘(a b c c c a))
NIL
9/Định nghĩa vị từ RIGHTP có ba tham số là độ dài ba cạnh của một tam giác(có thể
không là tam giác thật sự). Do biểu diễn số thực là không chính xác nên vị từ này sẽ
trả về T nếu tổng bình phương của hai cạnh ngắn nằm trong khoảng 2% của bình
phương độ dài cạnh lớn nhất(giả sử tham số đầu tiên là cạnh dài nhất)
Ví dụ:
* (rightp 5 4 3)
T
* (rightp 5 3 3)
NIL
10/Hãy đánh giá kết quả của các dạng phát biểu sau
(and (listp pi) (setf result ‘set-in-first-and))
result
(and (numberp pi) (setf result ‘set-in-second-and))
result
11/Viết các dạng IF tương đương với (ABS X), (MIN A B), và (MAX A B)
12/Kết hợp các dạng COND để tạo ra cùng một kết quả như (NOT U), (OR X Y Z),
và (AND A B C)
13/Định nghĩa thủ tục CHECK-TEMPERATURE có một tham số. Thủ tục này sẽ trả
về RIDICULOUSLY-HOT nếu tham số nhập vào lớn hơn 100, trả về
RIDICULOUSLY-COLD nếu tham số nhập vào nhỏ hơn 0 và trả về OK với các giá
trị còn lại
14/Viết thủ tục đệ qui phần đuôi (tail recursive) SKIP-FIRST-N để loại bỏ n phần tử
đầu tiên của danh sách đưa vào và trả về phần còn lại
Ví dụ:
* (skip-first-n 3 ‘(a b c d e f g h i))
(D E F G H I)
15/Viết một phiên bản khác không dùng đệ qui tương tự như câu trên.(giả sử danh
sách có ít nhất n phần tử)
16/Viết một cặp thủ tục(một có đệ qui và một không) trả về n phần tử đầu tiên trong
danh sách
17/Trong LISP các primitives 1- và 1+ dùng để giảm hay tăng một số lên một đơn vị.
Hãy dùng hai primitives này để viết một thủ tục ADD để cộng hai số mà không sử
dụng phép +. Giả sử là cả hai số đều là số dương.
18/Hãy cho biết thủ tục sau đây làm gì:
(deffun mystery (s)
(cond ((null s) 1)
((atom s) 0)
(t (max (+ (mystery (first s)) 1)
(mystery (rest s))
)
)
)
)
19/Hãy cho biết thủ tục sau đây làm gì:
(defun strange(l)
(cond ((null l) nil)
((atom l) l)
(t (cons (strange (first l))
(strange (rest l)))
)
)
)
20/Định nghĩa vị từ PRESENTP để xác định xem một atom có nằm trong một biểu
thức hay không. Chú ý là vị từ này khác với member ở chỗ nó tìm trong các thực thể ở
tất cả các mức (level) còn member chỉ tìm ở mức cao nhẩt (top-level).
Ví dụ:
* (setf formula ‘(sqrt (/ (+ (exp x 2) (exp y 2)) 2)))
* (presentp ‘x formula)
T
* (presentp ‘z formula)
NIL
Tiết 14: Lặp trên các số và danh sách
Sinh viên cần nắm được các nội dung sau:
• Làm cách nào để lặp lại một công việc với số lần cho trước (DOTIMES
primitive)
• Lặp lại công việc ứng với từng phần tử trong một danh sách (DOLIST
primitive)
• Cách sử dụng primitive lặp tổng quát DO
• Control Strategy
Bài tập / bài thực hành:
1/Định nghĩa chương trình con tính giai thừa DOTIMES-FACTORIAL sử dụng dạng
lặp DOTIMES. (0!=1)
2/Định nghĩa chương trình con COUNT-OUTLYERS để đếm số phần tử nhỏ hơn
nhiệt độ đông đặc hay lớn hơn nhiệt độ sôi trong một danh sách (đo bằng độ F:
freezing: 32 - boiling: 212) bằng cách sử dụng COUNT-IF thay cho DOLIST
3/Viết chương trình con LIST-OUTLYERS để tạo ra danh sách các phần tử từ danh
sách nhập vào(thông qua tham số) nhỏ hơn nhiệt độ đông đặc và lớn hơn nhiệt độ sôi
sử dụng DOLIST thay cho REMOVE-IF-NOT
4/Viết chương trình con LIST-OUTLYER-COUNTS để đếm các nhiệt độ dưới nhiệt
độ đông đặc và nhiệt độ sôi trong danh sách một cách riêng biệt và trả về kết quả dưới
dạng danh sách (dùng DOLIST)
5/Viết chương trình con DOLIST-MEMBER sử dụng phương pháp lặp dựa theo
chương trình con RECURSIVE-MEMBER(sử dụng phương pháp đệ qui) như sau:
(defun recursive-member (item l)
(cond ((endp l) nil)
((eql item (first l)) t)
(t (recursive-member item (rest l)))
)
)
Chú ý rằng khác với hàm MEMBER đã có sẵn, hai phiên bản MEMBER này trả về T
khi tìm được phần tử
6/Viết thủ tục DOLIST-REVERSE làm việc tương tự như REVERSE nhưng sử dụng
DOLIST
7/Định nghĩa chương trình con DO-FACTORIAL để tính giai thừa của một số sử
dụng DO với phần body là empty.
8/Viết lại hàm DO-MEMBER, một phiên bản lặp của RECURSIVE-MEMBER sử
dụng DO. Giống như MEMBER hàm này trả về phần còn lại của danh sách khi phần
tử được tìm thấy.
(defun recursive-member (item l)
(cond ((endp l) nil)
((eql item (first l)) l)
(t (recursive-member item (rest l)))
)
)
9/Viết thủ tục DO-REVERSE làm việc tương tự như REVERSE nhưng sử dụng DO
Tài liệu tham khảo:
1/Patrick Henry Winston and Berthold Klaus Paul Horn (1988) LISP. Addison-
Wesley.
2/
Các file đính kèm theo tài liệu này:
- de_cuong_mon_hoc_thuc_hanh_ngon_ngu_lap_trinh.pdf