• Tính hữu dụng Pragmatics của một ngôn ngữ lập trình mô tả các mức độ thành công mà một ngôn ngữ lập trình đáp ứng các mục tiêu của mô hình tính toán và tiện ích của nó đối với các lập
Trang 1PHƯƠNG PHÁP LẬP TRÌNH
(30 tiết LT)
Trang 2Nội dung
• Chương 1 Mở đầu
• Chương 2 Lập trình hàm
• Chương 3 Lập trình cấu trúc
• Chương 4 Lập trình hướng đối tượng
• Chương 5 Lập trình hướng đối tượng trong một số ngôn ngữ
• Chương 6 Các phương pháp lập trình trong F#
Trang 3
Chương 1 Mở đầu
Trang 4• Chương trình (program) là việc chỉ định một sự tính toán
• Ngôn ngữ lập trình (programming language) là k{ hiệu để viết các
chương trình
• Cú pháp (syntax) của một ngôn ngữ lập trình xác định cấu trúc hoặc
dạng của chương trình
• Ngữ nghĩa (semantics) của một ngôn ngữ lập trình mô tả quan hệ giữa
một chuowng trình và mô hình tính toán
• Tính hữu dụng (Pragmatics) của một ngôn ngữ lập trình mô tả các mức
độ thành công mà một ngôn ngữ lập trình đáp ứng các mục tiêu của mô hình tính toán và tiện ích của nó đối với các lập trình viên
• Một chương trình (program) có thẻ xem như là một hàm:
Output = Program(Input)
Program = Mô hình của một miền bài toán
Thực hiện một chương trình = Sự mô phỏng của miền bài toán
Trang 5Dữ liệu
• Dữ liệu (Data): Trong mọi trường hợp các đối tượng dữ lêệu
được xem như là trung tâm của các chương trình
• Các giá trị của dữ liệu được phân thành 2 nhóm riêng biệt: giá
trị đơn (primitive) và hỗn hợp (compound)
• Các giá trị đơn (primitive values) thường là các giá trị số, logic,
ký tự Liên hợp với các giá trị đơn thường là các toán tử (như các toán tử số học, toán tử logic )
• Các giá trị hỗ hợp (composite values) thường là các mảng
(arrays), các bản ghi (records), các giá trị định nghĩa đệ quy
(recursively defined values) Liên hợp với các giá trị hỗn hợp thường là các toán tử khởi tạo giá trị, các toán tử truy xuất mỗi thành phần của giá trị
Trang 6
Các loại giá trị dữ liệu
• Các giá trị Boolean (biểu diễn giá trị logic, nói chỉ sử dụng 1 bit dữ liệu)
• Các giá trị nguyên (Integer) (miền giá trị phụ thuộc vào số byte được sử dụng để lưu trữ)
• Các số tự nhiên (Natural number)
• Các số hữu tỷ (Rational number) (được biễu diễn bởi cặp số nguyên)
• Các giá trị thực (Real number)
• Các giá trị ký tự (Character)
• Các giá trị liệt kê (Enumeration)
• Các kiểu dữ liệu trừu tượng (Abstract data types)
(thường sử dụng kiểu con trỏ để tham chiếu)
Trang 7Một vài mô hình tính toán
Mô hình hàm (Functional Model)
• Mô hình hàm bao gồm một tập các giá trị, các hàm và các toán
tử trên hàm
• Một chương trình là một tập các định nghĩa của các hàm
• Sự tính toán là sự ứng dụng của hàm (giá trị của biểu thức)
Lập trình hàm
Trang 8Ví dụ: Công thức cho độ lệch chuẩn là:
Người ta áp dụng hai hàm bậc cao là map và fold Hàm map áp dụng
một hàm cho mỗi phần tử trong danh sách và hàm fold làm giảm một danh sách bằng cách áp dụng một hàm cho phần tử đầu tiên của
danh sách, kết quả của hàm là phần còn lại của danh sách Chương trình hàm viết như sau:
) (
Trang 9Mô hình Logic (Logic Model)
• Bao gồm một tập các giá trị, các định nghĩa về quan hệ và các luật suy diễn
• Chương trình logic bao gồm các định nghĩa về các quan hệ và một sự tính toán là một phép thử
• Ví dụ 1: Chu vi của đường tròn:
Trang 101a human(Socrates) Sự kiện (Fact) 1b human(Penelope) Sự kiện (Fact)
2 mortal(X) if human(X) Luật (Rule)
4b ¬human(Y) 5a Y = Socrates Từ 1 và 4 5b Y = Penelope
6 Mâu thuẩn 5a, 4b, và 1a; 5b, 4b và 1b
Lập trình logic:
Trang 11Mô hình mệnh lệnh (Imperative Model)
• Mô hình mệnh lệnh bao gồm một tập các giá trị chứa trạng thái và toán tử ấn định
để thay đổi trạng thái đó Trạng thái là tập các cặp (tên – giá trị) (name-value) của các hằng và biến
• Chương trình là chuổi các ấn định và sự tính toán là chuổi các trạng thái Mỗi bước trang tính toán là kết quả của một toán tử được ấn định
Trang 12• Mô hình mệnh lệnh thường được gọi là mô hình thủ tục (procedural model) vì các
nhóm toán tử được trừu tượng hoá thành các thủ tục
Trang 13Mẫu hình lập trình
• Một mẫu hình lập trình (programming paradigm) là một kiểu
lập trình mà nó là kiểu có tính mẫu hình trong tiến hành về
công nghệ phần mềm
Chẳng hạn: Lập trình hàm, lập trình logic, Lập trình cấu trúc
Lập trình hướng đối tượng
• Một mẫu hình lập trình cung cấp và xác định quan điểm mà
người lập trình về sự thực thi của chương trình
Ví dụ: trong lập trình hướng đối tượng, các lập trình viên có thể xem một
chương trình như là một tập họp của các đối tượng có tính tương tác,
trong khi đó, trong lập trình hàm, một chương trình có thể được xem như
là một chuỗi các đánh giá của các hàm vô hướng
• Các nhóm khác nhau trong công nghệ phần mềm đề xướng
các phương pháp khác nhau, các ngôn ngữ lập trình khác
nhau (tức là các mẫu hình lập trình khác nhau)
Trang 14• Một số ngôn ngữ được thiết kế để hỗ trợ một mẫu hình đặc thù
Ví dụ:
- Haskell: hỗ trợ lập trình hàm
- Pascal: hỗ trợ lập trình cấu trúc
- Java: hỗ trợ lập trình hướng đối tượng
- Số ngôn ngữ khác lại hỗ trợ nhiều mẫu hình (Python,Common, Lisp)
• Quan hệ giữa các mẫu hình lập trình và các ngôn ngữ lập trình có thể phức tạp vì một ngôn ngữ có thể hỗ trợ nhiều mẫu hình lập trình
Ví dụ: C++ được thiết kế để hỗ trợ các phần tử của lập trình thủ tục, lập trình
hướng đối tượng
• Mặc dù vậy, những người thiết kế và những người lập trình quyết định làm thế nào để xây dựng một chương trình dùng các phần tử của mẫu hình
Ví dụ: Người ta có thể viết một chương trình hoàn toàn theo kiểu lập trình thủ
tục trong C++, cũng có thể viết chương trình hoàn toàn hướng đối tượng, hay viết chương trình có các phần tử của cả hai mẫu hình
Trang 16Chương 2
Lập trình hàm
Trang 17• Mô hình tính toán dựa trên các khái niệm toán học của hàm
• Mỗi hàm có thể không đối số hoặc nhiều đối số Kết quả của hàm là một giá trị xác định hoặc dự báo
• Ngôn ngữ lập trình hàm: FP, Haskell, Gopher…
1 Lập trình hàm
Trang 18• Số tự nhiên: Toán học: 1,2…
Khoa học tính toán: 0,1,2…
• Ví dụ về một hàm đơn giản: Hàm tính giai thừa:
fact(n) = 1 x 2 x 3… x n với fact(0) =1
• Có thể được viết theo các dạng:
• Dễ thấy rằng, định nghĩa sau là tương đương với 2 định nghĩa trước (có thể chứng minh bằng quy nạp)
2 Định nghĩa của hàm
Trang 193 Nhìn qua dạng thức định nghĩa hàm trong lập trình hàm:
• Xét hàm fact(n) với định nghĩa toán học:
Trang 20
Cách 1: Đ/n thông qua biểu thức
fact1 :: Int -> Int fact1 n = if n==0 then 1 else n* fact1 (n-1)
-Dòng 1: Xác định kiểu cho hàm fact1 theo cú pháp object :: type
fact1 được định nghĩa như là một hàm (ký hiệu ->) với một tham
số có kiểu Int (thứ nhất) và kiểu trả lại của hàm là Int (thứ hai)
(Gopher không định nghĩa tập tự nhiên nên tạm sử dụng kiểu Int)
-Dòng 2: Khai báo nội dung của hàm fact1, nó có dạng:
fname params = body
Trong đó: fname: Tên của hàm
params: các tham số của hàm (có thể không có)
body : một biểu thức xác định giá trị của hàm
ví dụ trên là biểu thức if – then - else
Trang 21Cách 2: Lập các trường hợp
• Lập các trường hợp cho việc kiểm tra các phương trình điều kiện Nếu trường hợp nào đúng thì thực hiện việc lấy giá trị theo trường hợp đó
• Khi thực hiện, hàm sẽ được duyệt từ trên xuống dưới các trường hợp
để kiểm tra điều kiện
• Có thể thay otherwise bằng điều kiện n>=1 để khẳng định chỉ xét trong phạm vi số tự nhiên
Trang 25Ví dụ về file nguồn facts.gs cho gopher
Trang 26Một số lệnh thông dịch của gopher
Trang 27Ví dụ về thực hiện tính biểu thức và hàm thư viện trên dòng lệnh bằng gopher
Khoảng thời gian cần tính và
số ô nhớ được sử dụng
Trang 29Ví dụ về việc nộp và thực hiện các hàm trong chương trình
• Nộp file chương trình facts.gs nói trên
Trang 30• Liệt kê tên hàm trong chương trình
• Gọi thực hiện các hàm trong chương trình
Trang 325 Cơ bản về lập trình hàm
bằng Gopher
Trang 335.1 Các kiểu định nghĩa sẵn (built-in types)
Giá trị: True, False
Toán tử : && (and) || (or) và not
-Bao trong cặp dấu nháy đơn „ : „a‟, „A‟
- Kí tự escape : „\n‟ , „\t‟ , „\\‟ , „\‟‟
- Viết dụng mã : „\65‟ , „\x41‟ đều cho „A‟
Trang 34- Nếu t1 và t2 là các kiểu thì tham số kiểu là t1 và hàm có kiểu là t2
- Tên hàm và biến bắt đầu bởi một chữ cái (a z) thường, sau đó có thể
là chử cái (hoa, thường), chử số, dấu nháy đơn („), dấu gạch dưới (_)
- Hàm có thể có nhiều tham số Ví dụ hàm cộng 2 số nguyên:
f x y = x +y ( add x y)
được hiểu như là : f x + y = (f x) + y
Vì vậy tham số được khai báo:
Hoặc
Trang 35 Kiểu danh sách là kiểu có cấu trúc đầu tiên của Gopher, nó là một chuổi các phần tử cũng kiểu giá trị
Khai báo [t] là khai báo kiểu danh sách có các phẩn tử có giá trị kiểu t
Ví dụ [Int]
Một danh sách có thể rỗng Được ký hiệu []
Một danh sách khác rỗng có một phần tử đầu danh sách (head element)
và phần đuôi của danh sách (tail)
Toán tử : (dấu hai chấm) biểu diễn phần tử đầu và phần đuôi của danh sách Nó có dạng head:tail
Ví dụ: [] 2: [] 2: (3: [])
5: (3: (2 : []) có thể viết : 5:3:2:[] hoặc [5,3,2]
• Có 2 hàm thực hiện trên kiểu danh sách là head và tail:
Ví dụ: head [5,3,2] cho lại 5
tail [5,3,2] cho danh sách [3,2]
Trang 36• Là kiểu đã được định nghĩ như là mảng (danh sách) các ký tự:
• Hằng chuổi có thể được viết các dạng khác nhau:
• Vì là danh sách nên có thể áp dụng các hàm head và tail:
Trang 37Ví dụ về hàm tính độ dài chuổi (len)
Hàm thực hiện như sau:
Có thể mở rộng hàm len để tính số phần
tử của một danh sách với:
len :: [a] -> Int
Trang 38- t1, t2,…, tn là các kiểu (có thể khác nhau)
- Không giống như list, tuple có các phần tử không nhất thiết là
cùng kiểu và số phần tử của tuple là cố định Nó tương tự như kiểu Record trong Turbo – Pascal
- Ví dụ về tuple:
Trang 395.2 Lập trình với list
• Tổng của một list (sumlist)
- Cho danh sách gồm các phần tử nguyên v1, v2, v3, v4, … ,vn
- Tính tổng S = v1+ v2 + v3+ … + vn
- Xây dựng hàm sumlist như sau:
- Có thể thay dòng thứ 3 bởi:
Trang 40• Hàm tính độ dài của một list (length’)
Trong hàm này, ký hiệu (_) được hiểu như là “không quan tâm” đến giá trị của phần tử head
Trang 41• Bỏ đi các phần tử trùng lặp trong list
Để ý rằng, dòng thứ 2 chỉ thực hiện khi danh sách có không ít hơn 2 phần tử
Trang 42• Một số mẫu khác
Dưói đây là một số mẫu tham số, đối số tương ứng và kết quả của việc thử
Trang 435.3 Các toán tử infix
Các toán tử infix, infixl, infixr được sử dụng để định nghĩa thứ tự thực hiện các toán tử trong biểu thức
- infix : tự do
- infixl : từ trái sang phải
- infixr : từ phải sanf trái
Ví dụ về các toán tử infix chuẩn:
Trang 445.4 Các kiểu đệ quy
• Nối danh sách (toán tử ++)
- Tức là nối danh sách thứ hai vào sau danh sách thứ nhất để được một danh sách
- Hàm nối 2 danh sách được ký hiệu theo kiểu toán tử ++
- Đặt infix mức 5 cho toán tử ++ (mở rộng thêm infixr 5):
infixr 5 ++
- Định nghĩa toán tử ++
Trang 45Ví dụ thực hiện toán tử ++
Trang 47• Đảo các phẩn tử của list (rev)
Trong đó toán tử ++ chính là toán tử nối chuổi ở trên
Ví dụ:
Trang 49• Đảo với đệ quy phần đuôi của list
Trang 50• Các định nghĩa cục bộ (let và where)
let
Let thường được sử dụng trong các tập định nghĩa lồng nhau Nó có
dạng:
Let được sử dụng bất kỳ ở đâu xuất hiện một biểu thức
Ví dụ: Hàm f sau đây lập một danh sách mà mỗi phần tử là bình phương của danh sách tăng từ 1 (1,2,3…)
Trang 51 square là hàm một biến
one là một hàm không tham số (nó là một hằng = 1)
(y: ys) biểu thị một mẫu đối sánh của đối số xs của hàm f
Tham chiếu y hoặc ys của đối số xs của f có thể gây lỗi khi xs là rỗng
Các định nghĩa cục bộ square, one, y và ys có phạm vi sử dụng trong
biểu thức sau in
Các định nghĩa cục bộ có thể truy xuất các thành phần thuộc phạm vi của nó (outer) Chẳng hạn: định nghĩa (y:ys) truy xuất xs
Các định nghĩa cục bộ có thể đệ quy và gọi mỗi định nghĩa khác
Mệnh đề let trình diễn theo dạng bottom-up Nó xác định các thành phần trước khi được sử dụng
Trang 52where
-Tương tự như let nhưng theo kiểu top-down
- where sử dụng linh hoạt hơn let Nó cho phép định nghĩa các thành phần trong các mệnh đề trong khi let chỉ định nghĩa các thành phần
trong một biểu thức (sau in)
- Ví dụ:
Trong ví dụ này where định nghĩa cho các thành phần trong cả 3 mệnh
đề Lưu ý rằng, where được bắt đầu cùng cột với (=)
Trang 53Một ví dụ sử dụng định nghĩa cục bộ: Số Fibonacci
Số Fibonacci: f(0) = 0
f(1) = 1
f(n+2) = f(n) + f(n+1)
Định nghĩa hàm fib theo công thức trên:
Trong định nghĩa trên, hàm fib sử dụng n+2 mẫu để đối sánh các số
tự nhiên >=2
Trang 54Định nghĩa sau đây được coi là có hiệu suất cao hơn khi sử dụng đệ quy với việc cộng 2 số:
Trang 56• Ngắt một list (take và drop)
take và drop là hai toán tử chuẩn
take n xs : cho lại n phần tử đầu tiên của danh sách xs Nó được định nghĩa như là:
drop n xs : bỏ đi n phần tử đầu tiên của danh sách xs Nó được định nghĩa như là:
Ví dụ:
Trang 57• Liên hợp list (zip)
zip là toán tử chuẩn, cho phép hợp hai danh sách thành một danh sách theo kiểu ghép cặp các phần tử tương ứng
Ví dụ:
zip được định nghĩa như là zip‟ dưới đây:
Trang 585.6 Một ví dụ: Xây dựng tập số hữu tỷ
• Số hữu tỷ
Toán học: số hữu tỷ được định nghĩa như là: x/y với y<>0 Gopher : Định nghĩa như là một tuple:
Type Rat = (Int, Int)
Ví dụ: (1,7), (-1,-7), (3,21) đều biểu diễn số 1/7
Trang 59• Chuẩn hoá số hữu tỷ
- Chuyển (a,b) thành (x,y) trong đó x,y là nguyên tố cùng nhau
- Quy ước (0,y) = (0,1)
- Hàm chuẩn hoá số hữu tỷ:
Trang 60Việc xây dựng hàm normRat dựa vào các hàm:
signum: hàm chuẩn lấy dấu của một số -1 (âm) , 0 (không), 1 (dương)
Nó được định nghĩa như là:
a được khai báo là một đối tượng thuộc lớp Num và lớp Ord
gcd: hàm chuẩn cho lại ước số chung lớn nhất Nó được định nghĩa như là:
abs: hàm chuẩn cho lại trị tuyệt đối của một số
error: hàm chuẩn hiển thị thông báo lỗi lên màn hình
showRat: hàm hiển thị số hữu tỷ lên màn hình (xem sau)
Trang 61• Các phép toán trên số hữu tỷ
Trang 62• Hiển thị số hữu tỷ
Trong đó hàm show là một hàm chuẩn Nó convert một số
nguyên thành dạng chuổi
Trang 636 Các hàm bậc cao 6.1 Hàm map
Xét hai hàm sau đây:
Bình phương mỗi phần tử trong list:
Độ dài mỗi list con trong list:
Trang 64Hàm map cho phép thực hiện một hàm f lên mỗi phần tử của một
danh sách Nó được định nghĩa như là:
Nếu áp dụng hàm map cho 2 hàm ví dụ trên, ta có:
Trang 656.2 Hàm filter
Xét hai hàm sau đây:
Hàm cho lại một list các số chẳn từ một list
Hàm cho lại một list bằng cách gấp đôi phần tử dương của một list
Trang 66Hàm chuẩn filter với một hàm điều kiện p (kiểu a->Bool) và một danh sách kiểu [a] cho lại một danh dách gồm các phần tử trong danh sách [a] thỏa hàm điều kiện p
Nó được định nghĩa như là:
Áp dụng hàm filter, các hàm trên có thể định nghĩa lại như sau:
Trang 676.3 Các hàm Fold
Xét hai hàm sau đây:
Hàm nối các chuổi thành một chuổi
Hàm cho lại tổng các phần tử trong list
Trang 68Áp dụng hàm foldr , các hàm trên được định nghĩa như sau:
Trong đó: f là một toán tử nhị phân có dạng (a->b->b) Foldr thực hiện kiểu như:
Hàm foldr được định nghĩa như sau:
Hàm foldr
Áp dụng khác:
Trang 69Hàm foldl
Nó thực hiện kiểu như:
Ví dụ áp dụng:
Trang 706.4 Tính bộ phận
Xét hai hàm sau:
Cả hai đêu cho cùng kết quả nhưng khác nhau về đối số:
add: đối số là một 2-tiple và cho lại một Int
add‟: đối số là một Int và cho lại một hàm (Int->Int)
Do đó:
add 3 Lỗi
add‟ 3 được hiểu là gán 3 cho đối số của nó ((add‟ 3) 4) -> gán x, y với 3 và 4 và được 3+4 Tức: