« Scheme demonstrate that a very small number of rules for forming expressions, with no restrictions on how they are composed, suffice to form a pratical and efficient programming lang[r]
(1)ĐẠI HỌC ĐÀ NẴNG
TRƯỜNG ĐẠI HỌC BÁCH KHOA
KHOA CÔNG NGHỆ THÔNG TIN
G
GIIÁÁOO TTRRÌÌNNHH L
LẬẬPP TTRRÌÌNNHH HHÀÀMM V
VÀÀ LLẬẬPP TTRRÌÌNNHH LLƠƠGGIICC
PGS.TS PHAN HUY KHÁNH biên soạn
(2)Mục lục
CHƯƠNG CÁC NGÔN NGỮ LẬP TRÌNH 5
I MỞĐẦUVỀNGƠNNGỮLẬPTRÌNH
I.1 Vài nét lịch sử
I.2 Định nghĩa ngơn ngữ lập trình
I.3 Khái niệm chương trình dịch
II PHÂNLOẠICÁCNGƠNNGỮLẬPTRÌNH
III NGƠNNGỮLẬPTRÌNHMỆNHLỆNH 11
IV CƠSỞCỦACÁCNGƠNNGỮHÀM 12
CHƯƠNG NGÔN NGỮ SCHEME 17
I GIỚITHIỆUSCHEME 17
II CÁCKIỂUDỮLIỆUCỦASCHEME 18
II.1 Các kiểu liệu đơn giản 18
II.1.1 Kiểu số 18
II.1.2 Kiểu lơgích vị từ 20
II.1.3 Ký hiệu 21
II.2 Khái niệm biểu thức tiền tố 23
II.3 S-biểu thức 24
III CÁCĐỊNHNGHĨATRONGSCHEME 25
III.1 Định nghĩa biến 25
III.2 Định nghĩa hàm 26
III.2.1 Khái niệm hàm Scheme 26
III.2.2 Gọi hàm sau định nghĩa 26
III.2.3 Sử dụng hàm bổ trợ 27
III.2.4 Tính khơng định kiểu Scheme 28
III.3 Cấu trúc điều khiển 29
III.3.1 Dạng điều kiện if 29
III.3.2 Biến cục 30
III.3.3 Định nghĩa vị từ 32
III.4 Sơđồđệ quy sơđồ lặp 33
III.4.1 Sơđồđệ quy 33
III.4.2 Ví dụ 34
III.4.3 Tính dừng lời gọi đệ quy 36
III.4.4 Chứng minh tính dừng 37
III.4.5 Sơđồ lặp 37
III.5 Vào/ra liệu 39
III.6 Kiểu liệu phức hợp 40
III.6.1 Kiểu chuỗi 40
III.6.2 Kiểu liệu vectơ 43
III.6.3 Khái niệm trừu tượng hoá liệu 43
III.6.4 Định nghĩa bộđôi 45
III.6.5 Đột biến bộđôi 47
III.6.6 Ứng dụng bộđôi 47
III.7 Kiểu liệu danh sách 52
(3)III.7.3 Kỹ thuật đệ quy xử lý danh sách phẳng 64
III.7.4 Kỹ thuật đệ quy xử lý danh sách 67
III.8 Biểu diễn danh sách 70
III.8.1 Biểu diễn danh sách kiểu bộđôi 70
III.8.2 Danh sách kết hợp 73
III.8.3 Dạng quasiquote 76
III.9 Một số ví dụứng dụng danh sách 77
III.10 Sử dụng hàm 80
III.10.1 Dùng tên hàm làm tham đối 81
III.10.2 Áp dụng hàm cho phần tử danh sách 83
III.10.3 Kết trả hàm 85
III.11 Phép tính lambda 86
III.11.1 Giới thiệu phép tính lambda 86
III.11.2 Biễu diễn biểu thức lambda Scheme 87
III.11.3 Định nghĩa hàm nhờ lambda 88
III.11.4 Kỹ thuật sử dụng phối hợp lambda 90
III.11.5 Định nghĩa hàm nhờ tích luỹ kết 93
III.11.6 Tham đối hoá phần 95
III.11.7 Định nghĩa đệ quy cục 95
III.12 Xử lý hàm 97
III.12.1 Xây dựng phép lặp 97
III.12.2 Trao đổi thông điệp hàm 99
III.12.3 Tổ hợp hàm 101
III.12.4 Các hàm có số lượng tham đối 102
III.13 Một số ví dụ 104
III.13.1 Phương pháp xấp xỉ liên tiếp 104
III.13.2 Tạo thủ tục định dạng 105
III.13.3 Xử lý đa thức 106
III.13.4 Thuật toán quay lui 111
CHƯƠNG NGÔN NGỮ PROLOG 122
I GIỚITHIỆUNGƠNNGỮPROLOG 122
I.1 Prolog ngơn ngữ lập trình lơgich 122
I.1.1 Cú pháp Prolog 123
I.1.2 Các thuật ngữ 123
I.1.3 Các kiểu liệu Prolog 123
I.1.4 Chú thích 124
I.2 Các kiểu liệu sơ cấp Prolog 124
I.2.1 Kiểu số 124
I.2.2 Kiểu lôgich 125
I.2.3 Kiểu chuỗi ký tự 125
I.2.4 Kiểu nguyên tử 125
I.2.5 Biến 125
II SỰKIỆNVÀLUẬTTRONGPROLOG 125
II.1 Xây dựng kiện 125
II.2 Xây dựng luật 128
II.2.1 Định nghĩa luật 128
II.2.2 Định nghĩa luật đệ quy 132
II.2.3 Sử dụng biến Prolog 135
III KIỂUDỮLIỆUCẤUTRÚCCỦAPROLOG 136
III.1 Định nghĩa kiểu cấu trúc Prolog 136
(4)IV QUANHỆGIỮAPROLOGVÀLƠGICHTỐNHỌC 141
IV.1 Các mức nghĩa chương trình Prolog 142
IV.2 Nghĩa khai báo chương trình Prolog 142
IV.3 Khái niệm gói mệnh đề 143
IV.4 Nghĩa lôgich mệnh đề 144
IV.5 Nghĩa thủ tục Prolog 145
IV.6 Tổ hợp yếu tố khai báo thủ tục 152
V VÍDỤ :CONKHỈVÀQUẢCHUỐI 153
V.1 Phát biểu toán 153
V.2 Giải toán với Prolog 154
V.3 Sắp đặt thứ tự mệnh đề đích 157
V.3.1 Nguy gặp vịng lặp vơ hạn 157
V.3.2 Thay đổi thứ tự mệnh đề đích chương trình 159
VI SỐHỌC 162
VI.1 Các phép toán số học 162
VI.2 Biểu thức số học 162
VI.3 Định nghĩa phép toán Prolog 164
VI.4 Các phép so sánh số học 168
VI.5 Các phép so sánh hạng 169
VI.6 Vị từ xác định kiểu 170
VI.7 Một số vị từ xử lý hạng 171
VII ĐỊNHNGHĨAHÀM 172
VII.1 Định nghĩa hàm sử dụng đệ quy 172
VII.2 Tối ưu phép đệ quy 179
VII.3 Một số ví dụ khác vềđệ quy 180
VII.3.1 Tìm đường đồ thị có định hướng 180
VII.3.2 Tính độ dài đường đồ thị 181
VII.3.3 Tính gần chuỗi 181
VIII BIỂUDIỄNCẤUTRÚCDANHSÁCH 182
IX MỘTSỐVỊTỪXỬLÝDANHSÁCHCỦAPROLOG 184
X CÁCTHAOTÁCCƠBẢNTRÊNDANHSÁCH 185
X.1 Xây dựng lại số vị từ có sẵn 185
X.1.1 Kiểm tra phần tử có mặt danh sách 185
X.1.2 Ghép hai danh sách 186
X.1.3 Bổ sung phần tử vào danh sách 189
X.1.4 Loại bỏ phần tử khỏi danh sách 189
X.1.5 Nghịch đảo danh sách 190
X.1.6 Danh sách 190
X.1.7 Hoán vị 191
X.2 Một số ví dụ danh sách 192
X.2.1 Sắp xếp phần tử danh sách 192
X.2.2 Tính độ dài danh sách 193
(5)CHƯƠNG
CÁC NGƠN NGỮ LẬP TRÌNH
I. Mở đầu về ngơn ngữ lập trình
I.1. Vài nét về lịch sử
Buổi ban đầu
hững ngơn ngữ lập trình (programming language) máy tính điện tử ngơn ngữ máy (machine language), tổ hợp số hệ hai, hay hệ nhị phân, hay bit
(viết tắt binary digit) Ngôn ngữ máy phụ thuộc hồn tồn vào kiến trúc phần cứng máy tính quy ước khắt khe nhà chế tạo Để giải tốn, người lập trình phải sử dụng tập hợp lệnh điều khiển sơ cấp mà lệnh tổ hợp số
hệ hai nên gặp nhiều khó khăn, mệt nhọc, dễ mắc phải sai sót, lại khó sửa lỗi Từ năm 1950, để giảm nhẹ việc lập trình, người ta đưa vào kỹ thuật chương trình con (sub-program hay sub-routine) xây dựng thư viện chương trình (library) để cần gọi đến dùng lại đoạn chương trình viết
Ngôn ngữ máy tiến gần đến ngôn ngữ tự nhiên
Cũng từ năm 1950, ngôn ngữhợp dịch, hay hợpngữ(assembly) hay cịn gọi ngơn ngữbiểu tượng (symbolic) đời Trong hợp ngữ, mã lệnh địa toán hạng thay từ tiếng Anh gợi nhớ (mnemonic) ADD, SUB, MUL, DIV, JUMP tương ứng với phép tốn số học + - × /, phép chuyển điều khiển, v.v
Do máy tính hiểu ngơn ngữ máy, chương trình viết hợp ngữkhơng thể chạy mà phải qua giai đoạn hợp dịch (assembler) thành ngôn ngữ máy Tuy nhiên, hợp ngữ phụ thuộc vào phần cứng xa lạ với ngơn ngữ tự nhiên (natural language), người lập trình cịn gặp nhiều khó khăn giải tốn máy tính
Năm 1957, hãng IBM đưa ngôn ngữ FORTRAN (FORmula TRANslator) Đây ngôn ngữ lập trình gần gũi ngơn ngữ tự nhiên với cách diễn đạt toán học FORTRAN cho phép giải nhiều loại toán khoa học, kỹ thuật sau nhanh chóng ứng dụng rộng rãi ngày với kho tàng thư viện thuật toán đồ sộ tiện dụng Tiếp theo đời ngôn ngữ ALGOL 60 (ALGOrithmic Language) năm 1960, COBOL (Comon Business Oriented Language) năm 1964, Simula năm 1964, v.v
Phát triển ngôn ngữ lập trình
Theo phát triển hệ máy tính, ngơn ngữ lập trình khơng ngừng cải tiến hồn thiện để ngày đáp ứng nhu cầu người sử dụng giảm nhẹ cơng việc lập trình Rất nhiều ngơn ngữ lập trình đời tảng lý thuyết tính tốn (theory of computation) hình thành hai loại ngôn ngữ : ngôn ngữ bậc thấp ngôn ngữ bậc cao
Các ngôn ngữbậc thấp (low-level language), hợp ngữ ngôn ngữ máy, thường dùng
để viết chương trình điều khiển kiểm tra thiết bị, chương trình sửa lỗi (debugger) hay cơng cụ
(6)Các ngôn ngữ lập trình bậc cao (high-level language) phương tiện giúp người làm tin học giải vấn đề thực tế đồng thời nơi mà thành tựu nghiên cứu khoa học máy tính đưa vào Lĩnh vực nghiên cứu phát triển ngôn ngữ
lập trình vừa có tính truyền thống, vừa có tính đại Ngày nay, với tiến khoa học cơng nghệ, người ta sử dụng cơng cụ hình thức cho phép giảm nhẹ cơng việc lập trình từ lúc phân tích, thiết kế sử dụng ngơn ngữ lập trình
I.2. Định nghĩa một ngơn ngữ lập trình
Các ngơn ngữ lập trình bậc cao xây dựng mô ngôn ngữ tự nhiên, thường tiếng Anh (hoặc tiếng Nga năm trước đây) Định nghĩa ngơn ngữ lập trình định nghĩa văn phạm (grammar) để sinh câu ngôn ngữ Có thể hình dung văn phạm gồm bốn thành phần : bộ ký tự, từ vựng, cú pháp ngữ nghĩa.
1 Bộ ký tự(character set)
Gồm số hữu hạn ký tự (hay ký hiệu) phép dùng ngôn ngữ Trong máy tính cá nhân, người ta thường sử dụng ký tự ASCII Có thể hiểu ký tự có vai trị bảng chữ (alphabet) ngôn ngữ tự nhiên để tạo từ (word)
2 Bộ từ vụng (vocabulary)
Gồm tập hợp từ, hay đơn vị từ vựng (token), xây dựng từ ký tự Các từ
dùng để tạo thành câu lệnh chương trình phân loại tuỳ theo vai trò chức chúng ngơn ngữ Chẳng hạn chương trình Pascal sau :
program P;
var ×, y : integer; begin
read(x); y:=x+2; write(y) end
gồm đơn vị từ vựng :
Từ khoá (keyword), hay từ dành riêng (reserved word) : program, var, integer, begin, end
Tên, hay định danh (identifier) : read, write, P, x, y Hằng (constants) :
Phép toán (operators) : + , :=
Dấu phân cách (delimiters) : :, (, ),
3 Cú pháp (syntax)
Cú pháp quy định cách thức kết hợp ký tự thành từ, kết hợp từ thành câu lệnh (statement hay instruction), kết hợp câu lệnh thành chương trình hồn chỉnh
mặt văn phạm Có thể hình dung cách kết hợp giống cách đặt câu ngôn ngữ tự
(7)Ví dụ I.1 : Trong ngơn ngữ Pascal (hoặc phần lớn ngôn ngữ lập trình), tên gọi, hay
định danh (identifier) có sơđồ cú pháp sau :
Hình 0.1 Sơđồ cú pháp tên ngôn ngữ Pascal
Trong sơđồ cú pháp, hình chữ nhật phải thay hình trịn Quá trình thay thực thứ tự theo chiều mũi tên nhận câu Chẳng hạn «đọc» sơđồ sau : tên phải bắt đầu chữ, chữ
hoặc số tuỳ ý, chữ chũ A Za z, số chũ số Như vậy, Delta, x1, x2, Read, v.v tên viết đúng, cịn 1A, β, π, bán kính, v.v khơng phải tên vi phạm quy tắc cú pháp
Văn phạm BNF gồm dãy quy tắcc Mỗi quy tắc gồm vế trái, dấu định nghĩa ::= (đọc
được định nghĩa bởi) vế phải Vế trái ký hiệu phải định nghĩa, vế phải dãy ký hiệu, thừa nhận, định nghĩa từ trước đó, tuân theo quy ước EBNF dùng ký tự quy ước sau :
Ký hiệu Ý nghĩa
::=, →, = định nghĩa
{ } chuỗi hay nhiều mục liệt kê tuỳ chọn (option) [] hoặc mục liệt kê tuỳ chọn
< > mục liệt kê phải thay
| (theo nghĩa loại trừ) Các quy tắc BNF định nghĩa tên ngôn ngữ Pascal : <tên> ::= <chữ> { <chữ> | <số> }
<chữ> ::= ’A’ | | ’Z’ | ’a’ | | ’z’ <số> ::= ’0’ | | ’9’
Ví dụ I.2
Văn phạm ngôn ngữ lập trình đơn giản dạng EBNF sau : <program> ::= program <statement>* end
<statement> ::= <assignment> | <loop>
<assignment> ::= <identifier> := <expression> ; <loop> ::=
while <expression> do <statement>+ done <expression> ::=
<value> | <value> + <value> | <value> <= <value> <value> ::= <identifier> | <number>
<identifier> ::=
<letter>|<identifier><letter>|<identifier><digit> <number> ::= <digit> | <number><digit>
<letter> ::= ’A’ | | ’Z’ | ’a’ | | ’z’ <digit> ::= ’0’ | | ’9’
tên
chữ
số
chữ
chữ
A Z a z
số
(8)Một câu, tức chương trình đơn giản, viết văn phạm sau : program
n := 1 ;
while n <= 10 do n := n + 1 ; done end
4 Ngữ nghĩa (semantic)
Căn vào cú pháp ngôn ngữ lập trình, người lập trình viết chương trình gồm câu lệnh theo trình tự cho phép để giải tốn Để đạt mục đích đó, câu lệnh viết đắn mặt cú pháp, mà phải đắn mặt ngữ nghĩa, hay ý nghĩa logic câu lệnh Tính đắn mặt ngữ nghĩa cho phép giải tốn, chương trình chạy ln ln dừng, ổn định cho kết phù hợp với yêu cầu đặt ban đầu
I.3. Khái niệm về chương trình dịch
Chương trình viết ngơn ngữ lập trình bậc cao, hợp ngữ,
được gọi chương trình nguồn (source program)
Bản thân máy tính khơng hiểu câu lệnh chương trình nguồn Chương trình nguồn phải dịch (translate) thành một chương trình đích (target program) ngôn ngữ máy (là dãy số0 và 1), máy có thểđọc «hiểu» thực Chương trình đích cịn gọi chương trình thực hiện (executable program)
Chương trình trung gian đảm nhiệm việc dịch gọi chương trình dịch
Việc thiết kế chương trình dịch cho ngơn ngữ lập trình cho khó khăn phức tạp Chương trình dịch nguyên tắc phải viết ngôn ngữ máy để giải vấn đề
xử lý ngơn ngữ tính vạn chương trình nguồn Tuy nhiên, người ta thường sử
dụng hợp ngữ để viết chương trình dịch Bởi việc dịch chương trình hợp ngữ ngôn ngữ máy đơn giản nhiều Hiện nay, người ta viết chương trình dịch ngôn ngữ bậc cao công cụ chuyên dụng
Thơng thường có hai loại chương trình dịch, hay hai chếđộ dịch, trình biên dịch trình thơng dịch, hoạt động sau :
Trình biên dịch (compilater) dịch tồn chương trình nguồn thành chương trình đích sau bắt đầu tiến hành thực chương trình đích
Trình thơng dịch (interpreter) dịch câu lệnh chương trình nguồn tiến hành thực câu lệnh dịch đó, thực xong tồn chương trình
Có thể hiểu trình biên dịch dịch giả, trình thơng dịch thơng dịch viên
(9)II. Phân loại ngơn ngữ lập trình
Cho đến nay, có hàng trăm ngơn ngữ lập trình đề xuất thực tế, có số ngơn ngữđược sử dụng rộng rãi Ngồi cách phân loại theo bậc nói trên, người ta cịn phân loại ngơn ngữ lập trình theo phương thức (paradigm), theo mức độ quan trọng (measure of emphasis), theo thế hệ (generation), v.v
Cách phân loại theo bậc hay mức (level) dựa mức độ trừu tượng so với yếu tố
phần cứng, chẳng hạn nhưlệnh (instructions) cấp phát nhớ (memory allocation)
Mức Lệnh Sử dụng nhớ Ví dụ
Thấp Lệnh máy đơn giản Truy cập cấp phát trực tiếp Hợp ngữ, Autocode Cao Biểu thức điều khiển
tường minh
Truy cập cấp phát nhờ phép toán, chẳng hạn new
FORTRAN, ALGOL, Pascal, C, Ada
Rất cao Máy trừu tượng Truy cập ẩn tựđộng cấp phát SELT, Prolog, Miranda
Hình 0.2 Ba mức ngơn ngữ lập trình.
Những năm gần đây, ngơn ngữ lập trình phát triển theo phương thức lập trình (cịn gọi phong cách hay kiểu lập trình) Một phương thức lập trình có thểđược hiểu tập hợp tính trừu tượng (abstract features) đặc trưng cho lớp ngơn ngữ mà có nhiều người lập trình thường xuyên sử dụng chúng Sơđồ sau minh hoạ phân cấp phương thức lập trình :
Hình 0.3 Phân cấp phương thức lập trình
Sau số ngơn ngữ lập trình quen thuộc liệt kê theo phương thức :
Các ngơn ngữmệnh lệnh (imperative) có Fortran (1957), Cobol (1959), Basic (1965), Pascal (1970), C (1971), Ada (1979)
Các ngôn ngữđịnh hướng đối tượng (object-oriented)có Smalltalk (1969), C++ (1983), Eiffel (1986), Java (1991), C# (2000),
Các ngơn ngữ hàm (functional) có Lisp (1958), ML (1973), Scheme (1975), Caml (1987), Miranda (1982),
Các ngôn ngữdựa logic (logic-based) chủ yếu ngôn ngữ Prolog (1970) Ngôn ngữ thao tác sở liệu SQL (1980)
Các ngôn ngữ xử lý song song (parallel) Ada, Occam (1982), C-Linda, Ngồi cịn có số phương thức lập trình phát triển ứng dụng :
Lập trình phân bổ (distributed programming)
Lập trình ràng buộc (constraint programming)
Lập trình hướng truy cập (access-oriented programming)
Thủ tục đốHi tướượng ng song songXử lý Lôgic Hàm dCữơ li sệởu Mệnh lệnh
Phương thức lập trình
(10)Lập trình theo luồng liệu (dataflow programming), v.v
Việc phân loại ngơn ngữ lập trình theo mức độ quan trọng dựa cái gì (what)
thao tác (achieved), hay tính (computed), so với cách thao tác như nào (how) Một ngôn ngữ thể thao tác mà khơng cách thao tác gọi ngôn ngữ định nghĩa (definitional) hay khai báo (declarative) Một ngôn ngữ thể cách thao tác mà khơng thao tác gọi ngôn ngữ thao tác
(operational) hay không khai báo (non-declarative), ngơn ngữ mệnh lệnh.
Hình 0.4 Phát triển ngơn ngữ lập trình
Các ngơn ngữ lập trình phân loại theo hệ sau : Thế hệ : ngôn ngữ máy
Thế hệ : hợp ngữ
Thế hệ : ngôn ngữ thủ tục
Thế hệ : ngôn ngữ áp dụng hay hàm Thế hệ : ngôn ngữ suy diễn hay dựa logic Thế hệ : mạng nơ-ron (neural networks)
(11)III. Ngơn ngữ lập trình mệnh lệnh
Trong ngôn ngữ mệnh lệnh, người lập trình phải tìm cách diễn đạt thuật tốn, cho biết làm cách nào để giải toán cho Mơ hình tính tốn sử dụng tập hợp (hữu hạn) trạng thái thay đổi trạng thái Mỗi trạng thái phản ánh nội dung biến liệu
đã khai báo Trạng thái bị thay đổi lệnh điều khiển lệnh gán giá trị cho biến chương trình Chương trình biên dịch cho phép lưu giữ trạng thái
nhớ ghi, chuyển phép toán thay đổi trạng thái thành lệnh máy để
thực
Hình 0.5 Quan hệ tên biến, kiểu giá trị ngơn ngữ mệnh lệnh
Hình 0.5 minh họa cách khai báo liệu ngôn ngữ mệnh lệnh mối quan hệ theo mức Người ta phân biệt ba mức sau : mức ngôn ngữ liên quan đến tên biến, tên kiểu liệu cấu trúc lưu trữ ; mức chương trình dịch liên quan đến phương pháp tổ chức
nhớ mức máy cho biết cách biểu diễn theo bit giá trị liệu tương ứng Mỗi khai báo biến, ví dụint i, nối kết (bind) tên biến (i) với cấu trúc đặc trưng tên kiểu (int) với giá trị liệu biểu diễn theo bit nhờ lệnh gán i := 5 (hoặc nhờ lệnh vừa khai báo vừa khởi gán int i=5) Tổ hợp tên, kiểu giá trịđã tạo nên đặc trưng biến
Các ngôn ngữ mệnh lệnh sử dụng hiệu lập trình người lập trình
tác động trực tiếp vào phần cứng Tuy nhiên, tính thực dụng mệnh lệnh làm hạn chế trí tuệ người lập trình phải phụ thuộc vào cấu trúc vật lý máy tính Người lập trình ln có khuynh hướng suy nghĩ vị trí lưu trữ liệu đặt tên (nguyên tắc địa hoá) mà nội dung chúng thường xuyên bị thay đổi Thực tế có nhiều toán cần trừu tượng hoá giải (nghĩa không phụ thuộc vào cấu trúc vật lý máy tính), khơng địi hỏi tính thành thạo người lập trình, mà cịn địi hỏi kiến thức Tốn học tốt khả trừu tượng hoá họ
Từ lý mà người ta tìm cách phát triển mơ hình tương tác khơng phản ánh mối quan hệ với phần cứng máy tính, mà làm dễ dàng lập trình Ý tưởng mơ hình người lập trình cần đặc tả tính tốn mà khơng phải mơ tả cách tính
nào Sự khác «như nào» «cái gì», khác ngôn ngữ
mệnh lệnh ngôn ngữ khai báo, luôn rõ ràng Các ngơn ngữ khai báo thường khó cài đặt khó vận hành ngôn ngữ mệnh lệnh Các ngôn ngữ mệnh lệnh thường gần gũi người lập trình
Sau sốđặc trưng ngôn ngữ lập trình mệnh lệnh :
− Sử dụng nguyên lý tinh chế bước hay làm mịn dần, xử lý đối tượng
liệu đặt tên
Kiểu :
tập hợp giá trị
tập hợp phép toán cấu trúc lưu trữ
bit
dấu 214 213 22
21 20 biểu diễn theo bit :
0 0 1 ., −1, 0, 1,
+, −, ×, /,
Mức ngơn ngữ
Mức chương
trình dịch
Mức máy
Số
5
Tên kiểu
integer
Tên biến
(12)− Khai báo liệu để nối kết tên biến khai báo với kiểu liệu giá trị Phạm vi hoạt động (scope) biến chương trình xác định khai báo, toàn cục (global), cục (local)
− Các kiểu liệu thông dụng số nguyên, số thực, ký tự lôgic Các kiểu
được xây dựng nhờ kiểu cấu trúc Ví dụ kiểu mảng, kiểu ghi, kiểu tập hợp, kiểu liệt kê,
− Hai kiểu liệu có tên tương đương với nhau, hai cấu trúc liệu tương
đương có giá trị có phép tốn xử lý
− Trạng thái (bộ nhớ ghi) bị thay đổi lệnh gán Trạng thái (thiết bị ngoại vi) bị thay đổi lệnh vào-ra Giá trịđược tính từ biểu thức
− Các cấu trúc điều khiển tuần tự, chọn lựa (rẽ nhánh), lặp gọi chương trình
− Chương trình thường có hai dạng : dạng thủ tục (procedure) dạng hàm (function) Sự khác chủ yếu hàm trả giá trị, cịn thủ tục khơng khơng thiết trả giá trị Việc trao đổi tham biến (parameter passing) với chương trình theo trị (by value) theo tham chiếu (by reference)
− Sử dụng chương trình thường gây hiệu ứng phụ (side effect) làm thay
đổi biến tồn cục
− Một chương trình xây dựng theo bốn mức : khối (block), chương trinh con, đơn thể(module/packages) chương trình
IV. Cơ sở của ngơn ngữ hàm
Trong ngôn ngữ mệnh lệnh, chương trình thường chứa ba lời gọi chương trình (thủ tục, hàm) liên quan đến trình đưa vào liệu, xử lý liệu đưa kết tính tốn sau :
begin
GetDată ) ; { đưa vào } ProcessDatặ ); { xử lý }
OutPutResults( ); { xem kết } end
Trong ngơn ngữ lập trình hàm, lời gọi chương trình viết thành biểu thức đơn giản :
(process-data
(get-data ( ))))
Các ngôn ngữ hàm ngơn ngữ bậc cao, mang tính trừu tượng so với ngôn ngữ mệnh lệnh
Những người lập trình hàm thường tránh sử dụng biến tồn cục, đó, hầu hết người lập trình mệnh lệnh phải sử dụng đến biến tồn cục
Khi lập trình với ngơn ngữ hàm, người lập trình phải định nghĩa hàm tốn học dễ
suy luận, dễ hiểu mà không cần quan tâm chúng cài đặt máy
Những người theo khuynh hướng lập trình hàm cho lệnh chương trình viết ngơn ngữ mệnh lệnh làm thay đổi trạng thái toàn cục hồn tồn bất lợi Bởi nhiều phần khác chương trình (chẳng hạn hàm, thủ tục) tác động không trực tiếp lên biến làm chương trình khó hiểu Các thủ tục thường gọi sử dụng
(13)(correctness proof), cản trở tối ưu hóa (optimization), cản trở trình song song tự động (automatic parrallelization) chương trình
Một ngơn ngữ hàm, hay ngơn ngữ áp dụng (applicative language) dựa việc tính giá trị
của biểu thức xây dựng từ bên ngồi lời gọi hàm Ởđây, hàm hàm tốn học túy : ánh xạ nhận giá trị lấy từ miền xác định (domain) để trả giá trị
thuộc miền khác (range hay co-domain)
Một hàm có, khơng có, tham đối (arguments hay parameters) để sau tính tốn, hàm trả giá trị Chẳng hạn xem biểu thức + hàm tính tổng (phép +) hai tham đối
Ta thấy hàm không gây hiệu ứng phụ trạng thái chương trình, trạng thái trì cho tham đối hàm Tính chất đóng vai trị quan trọng lập trình hàm Đó kết hàm không phụ vào thời điểm (when) hàm
được gọi, mà phụ thuộc vào cách gọi tham đối.
Trong ngơn ngữ lập trình mệnh lệnh, kết biểu thức : f(x) + f(x)
có thể khác với kết : * f(x)
vì lời gọi f(x) làm thay đổi x biến tiếp cận f Trong ngơn ngữ lập trình hàm, hai biểu thức ln có giá trị
Do hàm không phụ thuộc nhiều vào biến tồn cục, nên việc lập trình hàm dễ
hiểu lập trình mệnh lệnh Ví dụ giả sử trình biên dịch cần tối ưu phép tính : f(x) + f(x)
thành :
2 * f(x)
Khi đó, trình biên dịch ngơn ngữ hàm luôn xem hai kết một, có tính qn kết trả hàm Tuy nhiên, trình biên dịch ngơn ngữ mệnh lệnh, ngơn ngữ Ada1 chẳng hạn, phải chứng minh kết lời gọi thứ hai không phụ thuộc vào biến bị thay đổi trình thực lời gọi thứ
Một trình biên dịch song song gặp phải vấn đề tương tự trình muốn gọi hàm theo kiểu gọi song song
Bên cạnh tính ưu việt, ta cần xem xét bất lợi vốn có lập trình hàm : nhược
điểm ngôn ngữ hàm thiếu lệnh gán biến tồn cục, khó khăn việc mơ tả cấu trúc liệu khó thực trình vào/ra liệu
Tuy nhiên, ta thấy thiếu lệnh gán biến toàn cục khơng ảnh hưởng hay khơng làm khó khăn nhiều cho việc lập trình Khi cần, lệnh gán giá trị cho biến mô cách sử dụng cấu tham biến hàm, chương trình viết ngơn ngữ mệnh lệnh
Chẳng hạn ta xét hàm P sử dụng biến cục bộx trả giá trị có kiểu
nào (SomeType) Trong ngơn ngữ mệnh lệnh, hàm P làm thay đổi x gán cho x
môt giá trị Trong ngơn ngữ hàm, P mơ thay đổi truyền giá trị
1
(14)mới x tham đối cho hàm phụ trợ thực phần mã lại P Chẳng hạn, thay đổi giá trị biến chương trình P :
function P(n: integer) −> SomeType ; x: integer := n +
begin
x := x * + return * g(x) end ;
ta viết lại sau :
function P(n : integer) −> SomeType ; x: integer := n +
begin
return Q(3*x + 1) % mô x := x * + end ;
trong đó, hàm Qđược định nghĩa sau :
function Q(x: integer) −> Some Type begin
return * g(x) end ;
Ta sử dụng kỹ thuật cho biến tồn cục Như vậy, việc mơ lập trình mệnh lệnh ngôn ngữ hàm cách mong muốn, làm
được
Một vấn để bật ngôn ngữ hàm thay đổi cấu trúc liệu Trong ngôn ngữ mệnh lệnh, thay đổi phần tử mảng đơn giản Trong ngôn ngữ hàm, mảng bị thay đổi Người ta phải chép mảng, trừ phần tử bị thay đổi, thay giá trị cho phần tử Cách tiếp cận hiệu so với phép gán cho phần tử
Một vấn đề khác lập trình hàm khả hạn chế giao tiếp hệ thống tương tác với hệđiều hành với người sử dụng Tuy nhiên nay, người ta có xu hướng tăng cường thư viện hàm mẫu xử lý hướng đối tượng giao diện đồ hoạ (GUI-Graphic User Interface) Chẳng hạn phiên thông dịch họ Lisp DrScheme, MITScheme, WinScheme
(15)Bài tập chương : ÔN LẠI THUẬT TỐN Tính gần giá trị hàm sau với độ xác e = 10-5
π 1
= − + − +
2n -1 <ε
2
x x x
1 + + + +
2 3× 5× × phần tử thứn < e S = - x + x
2! - x
3! + + (-1) x
n! +
2
n n cho đến xn
n! <ε
S x x x x n
n
= +1 + + + + +
2
2
! ! ! ( )!
x n n 10 ( )! <
−
y = x + x + + x có n > dấu
2 Tìm ước số chung lớn * số nguyên p, q
3 Cho danh sách số nguyên L số nguyên K, thực việc sau : a)Đếm số chia hết cho K L ?
b)Kiểm tra sốK có nằm danh sách L hay khơng ? c)Cho biết vị trí phần tửđầu tiên danh sách L K ? d)Tìm tất vị trí phần tử K danh sách L ? e)Thay phần tử K danh sách L phần tửK’ cho ?
4 Viết chương trình để xóa ba phần tửđầu tiên ba phần tử cuối danh sách Viết chương trình để xóa N phần tử danh sách Thất bại danh sách
khơng có đủ N phần tử
6 Viết chương trình để xóa N phần tử cuối danh sách Thất bại danh sách khơng có đủ N phần tử
7 Định nghĩa hai hàm even_length odd_length để kiểm tra số phân tử danh sách cho chẵn hay lẻ tương ứng
Ví dụ danh sách [a, b, c, d ] có độ dài chẵn, danh sách [ a, b, c ] có độ dài lẻ
Viết chương trình kiểm tra danh sách có phải tập hợp danh sách khác không ?
8 Viết chương trình để lấy phần tử thứ N danh sách Thất bại danh sách khơng có đủ N phần tử
Viết chương trình tìm phần tử lớn phần tử nhỏ danh sách số Viết chương trình để kiểm tra hai danh sách có rời (disjoint) không ?
(16)luôn thỏa mãn lần chuyển đĩa từ cọc sang cọc khác, cọc đĩa sau nhỏ chồng lên đĩa trước lớn đĩa lớn
11.Viết chương trình để tạo số nguyên tố sử dụng sàng Eratosthènes Chương trình khơng kết thúc Thử sử dụng kỹ thuật tính giá trị hàm theo kiểu khơn ngoan để có lời giải đơn giản hiệu
12.Cây nhị phân (binary tree) biểu diễn một danh sách gồm ba phần tử
liệu : nút gốc (root node), bên trái (left subtree) bên phải (right subtree) nút gốc Mỗi lại xem nhị phân Cây, rỗng (empty tree) biểu diễn danh sách rỗng Ví dụ cho nhị phân có nút [1, [2, [], []], [3, [4, [], []], []]] sau :
Hình 0.6 Cây nhị phân có nút
Viết chương trình duyệt theo thứ tự (trái-gốc-phải), trước (gốc-trái-phải) sau (trái- phải-gốc) ?
1
2
(17)CHƯƠNG
NGÔN NGỮ SCHEME
A line may take us hours, yet if it does not seem a moment's thought All our stitching and unstitching has been as nought
Yeats - Adam's Curse
I. Giới thiệu Scheme
cheme ngôn ngữ thao tác ký hiệu (symbolic manipulation) Guy Lewis Steele Jr Gerald Jay Sussman đề xuất năm 1975 MIT (Massachusetts Institute of Technology, Hoa Kỳ), sau phát triển nhanh chóng ứng dụng phổ biến Scheme ngôn ngữ thuộc họ Lisp mang tính sư phạm cao Scheme giải thích hợp toán toán học xử lý ký hiệu Theo W Clinger J Rees2 :
«Scheme demonstrate that a very small number of rules for forming expressions, with no restrictions on how they are composed, suffice to form a pratical and efficient programming language that is flexible enough to support most of the major programming paradigms in use today »
Tương tự ngơn ngữ hàm khác, Scheme có cú pháp đơn giản nên dễ lập trình Các cấu trúc liệu sở Scheme danh sách cây, dựa khái niệm vềkiểu liệu trừu tượng (data abstraction type) Một chương trình Scheme dãy định nghĩa hàm (hay
thủ tục) góp lại để định nghĩa nhiều hàm phức tạp Hoạt động lập trình Scheme tính giá trị biểu thức Scheme làm việc theo chếđộ tương tác (interaction) với người sử dụng
Mỗi vòng tương tác xảy sau :
Người sử dụng gõ vào biểu thức, sau dòng nhấn enter (↵) Hệ thống in kết (hoặc báo lỗi) qua dòng
Hệ thống đưa dấu nhắc (prompt character) chờ người sử dụng đưa vào biểu thức
Việc lựa chọn dấu nhắc tùy theo quy ước hệ thống, thông thường dấu lớn (>) dấu hỏi (?)3
Một dãy phép tính giá trị biểu thức vịng tương tác gọi chầu làm việc (session) Sau chầu, Scheme đưa thời gian số lượng nhớ (bytes) sử dụng
để tính tốn
Để tiện theo dõi, sách sử dụng quy ước sau : Kết tính tốn ghi theo sau dấu mũi tên ( >) Các thông báo lỗi sai đặt trước ba dấu (***)
Cú pháp biểu thức viết theo quy ước EBNF kiểu chữ nghiêng đậm Ví dụ : <e>
2Xem tài liệu định nghĩa ngôn ngữ Scheme tại địa chỉhttp://www.swiss.ai.mit.edu/~jaffer/r5rs_toc.html 3
(18)Để tiện trình bày tiếng Việt, số phần thích kết tính tốn khơng in theo kiểu chữ Courier
Chú thích Scheme
Chú thích (comment) dùng để diễn giải phần chương trình liên quan giúp người đọc dễ
hiểu, dễ theo dõi khơng có hiệu lực Scheme (Scheme bỏ qua phần thích thực hiện) Chú thích bắt đầu dấu chấm phẩy (;), viết dòng bất kỳ, từđầu dịng, cuối dịng Ví dụ :
; this is a comment line
(define x 2) ; định nghĩa biến x có giá trị
;;; The FACT procedure computes the factorial ;;; of a non-negative integer
(define fact (lambda (n)
(if (= n 0)
1 ; Base case: return (* n (fact (- n 1))))))
II. Các kiểu dữ liệu của Scheme
Kiểu liệu (data type) tập hợp giá trị có quan hệ loại với (related values) Các kiểu liệu xử lý tuỳ theo chất chúng thường có tính phân cấp Trong Scheme có hai loại kiểu liệu kiểu đơn giản (simple data type) kiểu phức hợp
(compound data type) Trong chương này, ta xét kiểu liệu đơn giản trước
II.1. Các kiểu dữ liệu đơn giản
Các kiểu liệu đơn giản Scheme bao gồm kiểu số (number), kiểu lơgích (boolean), kiểu ký tự(character) kiểu ký hiệu (symbol)
II.1.1. Kiểu số
Kiểu số Scheme số nguyên (integer), số thực (real), số hữu tỷ (rational) số
phức (complex ) sau :
Kiểu số Ví dụ
số nguyên 52
số thực 3.0, -2.5
số hữu tỷ 6/10, 23/5
số phức 3+4i,
Scheme không phân biệt số nguyên hay số thực Các số không hạn chế vềđộ lớn, miễn nhớ cho phép
Với số, Scheme sử dụng phép tốn số học thơng dụng +, -, *, /, max, min, phép lấy bậc hai √⎯ so sánh số học với số lượng đối số tương ứng :
(+ x1 xn) > x1 + + xn
(- x1 x2) > x1- x2
(* x1 xn) > x1 * * xn
(19)(quotient x1 x2) > phần nguyên (x1/ x2)
(remainder x1 x2) > phần dư phép chia nguyên (x1/ x2), lấy dấu x1
(modulo x1 x2) > phần dư phép chia nguyên (x1/ x2) , lấy dấu x2
(max x1 xn) > max (x1, , xn) (min x1 xn) > (x1, , xn) (sqrt x) > √⎯x
Các phép so sánh sau trả #t kết so sánh giá trịx1, , xn thoả mãn, ngược lại trả #f :
(= x1 xn) (< x1 xn) (<= x1 xn) (> x1 xn) (>= x1 xn) Ví dụ :
(* 9) > 362880
(= 5) > #f
(= 1 1 1) > #t
(< 5) > #t
(> 1) > #t
(<= 5) > #t
(>= 1) > #t
Thể tích hình cầu bán kính R : (* pi R R R)
Nhiệt độ Farenheit biểu diễn qua nhiệt độ Celsius C : (+ 32 (* 9/5 C))
Một biểu thức Scheme trộn lẫn lộn số nguyên số thực : (+ 2.3 5)
> 7.3
Phép tính số hữu tỷ : (* 2/3 5/2)
> 10/6
(20)> -2
Ký tự
Một ký tự (character) Scheme có dạng #\<char> Ví dụ : #\a
> #\a ;chữ a thường #\A
> #\A ;chữA hoa #\(
> #\( dấu ngoặc trái
Chuỗi
Chuỗi (string) kiểu liệu phức hợp Scheme, gồm dãy ký tự tuỳ ý đặt hai dấu nháy kép, dấu nháy kép giữ nguyên giá trị chuỗi :
”Chào bạn !”
> ” Chào bạn !”
Tên
Mọi ngơn ngữ lập trình sử dụng tên để định đối tượng cần xử lý Trong Scheme, tên tạo thành từ chữ cái, chữ số dấu đặc biệt, trừ # () [] dấu cách (space) dùng để phân cách đối tượng
Tên Scheme bắt đầu chữ không phân biệt chữ hoa chữ thường Viết pi hay PI tên Nên chọn đặt tên «biết nói» (mnemonic) sử dụng dấu nối (-) Chẳng hạn tên sau hợp lệ :
pi * pi-chia-2
x + a34kTMNs
soup <=? is-this-a-very-long-name? lambda V19a list->vector
II.1.2. Kiểu lơgích vị từ
Mọi ngơn ngữ lập trình sử dụng cấu trúc điều khiển sử dụng đến giá trị lơgích đó, cần biểu diễn giá trị lơgích Trong Scheme, có sẵn kiểu lơgích #t (true) #f(false)
Vị từ (predicate) hàm trả giá trị lơgích Theo quy ước, tên vị từđược kết thúc dấu chấm hỏi (?)
Thư viện Scheme có sẵn nhiều vị từ Sau số vị từ dùng để kiểm tra kiểu giá trị biểu thức :
(number? s) > #t s số thực, #f không (integer? s) > #t s nguyên, #f không (string? s) > #t s chuỗi, #f không (boolean? s) > #t s lơgích, #f không (procedure? s) > #t s hàm, #f khơng Ví dụ :
(string? 10)