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

Nghiên cứu lập trình phản ứng với ngôn ngữ ELM

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 (2.05 MB, 79 trang )

ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƢỜNG ĐẠI HỌC CÔNG NGHỆ

NGUYỄN NHƢ MINH

NGHIÊN CỨU LẬP TRÌNH PHẢN ỨNG VỚI NGÔN
NGỮ ELM

LUẬN VĂN THẠC SĨ CÔNG NGHỆ THÔNG TIN

Hà Nội - 2015
1


ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƢỜNG ĐẠI HỌC CÔNG NGHỆ

NGUYỄN NHƢ MINH

NGHIÊN CỨU LẬP TRÌNH PHẢN ỨNG VỚI NGÔN
NGỮ ELM

Ngành: Công nghệ thông tin
Chuyên ngành: Kỹ thuật phần mềm
Mã số: 60480103

LUẬN VĂN THẠC SĨ CÔNG NGHỆ THÔNG TIN

NGƢỜI HƢỚNG DẪN KHOA HỌC: PGS. TS. TRƢƠNG ANH HOÀNG

Hà Nội - 2015


2


LỜI CẢM ƠN
Trƣớc tiên tôi xin chân thành cảm ơn PGS.TS. Trƣơng Anh Hoàng đã tận
tình hƣớng dẫn, giúp đỡ tôi trong suốt quá trình thực hiện luận văn tốt nghiệp.
Tôi xin chân thành cảm ơn các thầy cô giáo khoa Công nghệ Thông tin,
trƣờng Đại học Công nghệ, Đại học Quốc gia Hà Nội, những ngƣời đã tận tình
truyền đạt các kiến thức, quan tâm, động viên trong suốt thời gian tôi học tập và
nghiên cứu tại Trƣờng.
Nhân đây cho phép tôi gửi lời cảm ơn tới nhóm các bạn học cùng lớp
K20CNPM, lớp chuyên ngành công nghệ phần mềm đã thƣờng xuyên quan tâm,
giúp đỡ, chia sẻ kinh nghiệm, cung cấp các tài liệu hữu ích trong suốt thời gian học
tập tại trƣờng.
Hà Nội, tháng 12 năm 2015
Tác giả luận văn

Nguyễn Như Minh

3


LỜI CAM ĐOAN
Tôi xin cam đoan bản luận văn “Nghiên cứu lập trình phản ứng với ngôn ngữ
Elm” là công trình nghiên cứu của tôi dƣới sự hƣớng dẫn khoa học của PGS.TS.
Trƣơng Anh Hoàng, tham khảo các nguồn tài liệu đã chỉ rõ trong trích dẫn và danh
mục tài liệu tham khảo. Các nội dung công bố và kết quả trình bày trong luận văn
này là trung thực và chƣa từng đƣợc ai công bố trong bất cứ công trình nào.

Hà Nội, tháng 12 năm 2015

Tác giả luận văn

Nguyễn Như Minh

4


MỤC LỤC
LỜI CẢM ƠN ............................................................................................................ 3
LỜI CAM ĐOAN....................................................................................................... 4
MỤC LỤC .................................................................................................................. 5
DANH SÁCH HÌNH VẼ ........................................................................................... 7
MỞ ĐẦU .................................................................................................................... 8
Lý do chọn đề tài ................................................................................................... 8
Mục đích nghiên cứu............................................................................................. 9
Đối tƣợng và phạm vi nghiên cứu......................................................................... 9
Kết cấu của luận văn ........................................................................................... 10
CHƢƠNG 1-GIỚI THIỆU VỀ LẬP TRÌNH PHẢN ỨNG..................................... 11
1.1 Giới thiệu lập trình phản ứng ........................................................................ 11
1.2 Lập trình phản ứng là luồng dữ liệu.............................................................. 13
1.3 Đặc điểm của lập trình phản ứng .................................................................. 17
1.4 Lập trình hàm phản ứng ................................................................................ 19
1.4.1 Classical FRP ....................................................................................... 19
1.4.2 Real-time FRP & Event-Driven FRP .................................................. 20
1.4.3 Arrowized FRP .................................................................................... 21
CHƢƠNG 2 – LẬP TRÌNH PHẢN ỨNG VỚI NGÔN NGỮ ELM....................... 23
2.1 Khái quát về ngôn ngữ lập trình hàm............................................................ 23
2.1.1 Định nghĩa ........................................................................................... 23
2.1.2 Tính khai báo của ngôn ngữ hàm ........................................................ 23
2.1.3 Một số khái niệm cơ bản trong ngôn ngữ hàm.................................... 25

2.2 Cơ bản về ngôn ngữ Elm .............................................................................. 29
5


2.2.1 Các cú pháp cơ bản .............................................................................. 29
2.2.2 Ví dụ về giao diện đồ họa trong Elm.................................................. 33
2.2.3 Các tín hiệu tƣơng tác trong Elm......................................................... 36
2.3 Các ƣu điểm của ngôn ngữ Elm .................................................................... 41
2.4 Các thao tác với tín hiệu trong Elm .............................................................. 43
2.5 Lập trình tƣơng tác ........................................................................................ 47
2.6 Gỡ lỗi trong Elm ........................................................................................... 49
2.7 Kiến trúc Elm trong lập trình trò chơi........................................................... 51
CHƢƠNG 3 – XÂY DỰNG ỨNG DỤNG TRÒ CHƠI HOCKEY ........................ 53
3.1 Mô tả trò chơi ................................................................................................ 53
3.2 Phân tích trò chơi .......................................................................................... 55
3.3 Xây dựng code chƣơng trình với ngôn ngữ Elm .......................................... 58
3.3.1 Xây dựng giao diện.............................................................................. 58
3.3.2 Xây dựng mô hình dữ liệu ................................................................... 62
3.3.3 Xây dựng tín hiệu đầu vào................................................................... 64
3.3.4 Cập nhật dữ liệu chƣơng trình ............................................................. 64
3.3.5 Thực thi và chạy chƣơng trình............................................................. 70
3.4 Nhận xét, đánh giá và thảo luận .................................................................... 71
3.4.1 Ƣu điểm của lập trình phản ứng .......................................................... 71
3.4.2 Một số khó khăn của lập trình phản ứng ............................................. 72
3.4.3 Ƣu điểm của ngôn ngữ Elm................................................................. 73
3.4.4 Nhƣợc điểm của ngôn ngữ Elm ........................................................... 75
KẾT LUẬN .............................................................................................................. 76
TÀI LIỆU THAM KHẢO ........................................................................................ 78
6



DANH SÁCH HÌNH VẼ
Hình 1.1: Sự truyển đổi giá trị liên tục của dòng theo tín hiệu chuột............ 16
Hình 1.2: Sơ đồ các đặc điểm của lập trình phản ứng ................................... 18
Hình 2.1: Hiển thị văn bản trong Elm............................................................ 32
Hình 2.2: Các Forms đồ họa đƣợc tạo ........................................................... 34
Hình 2.3: Tạo và kết hợp các hình dạng thành một thành phần .................... 36
Hình 2.4: Bảng các tín hiệu đầu vào trong Elm ............................................. 37
Hình 2.5: Theo dõi sự chuyển động của trỏ chuột [5] ................................... 38
Hình 2.6: Di chuyển đối tƣợng là hình tròn bằng các phím mũi tên ............. 41
Hình 2.7: Mô tả quá trình hoạt động của tín hiệu .......................................... 44
Hình 2.8: Elm’s Time Traveling Debugger ................................................... 51
Hình 3.1: Ca sử ngƣời chơi ............................................................................ 54
Hình 3.2: Ca sử dụng sân bóng ...................................................................... 55
Hình 3.3: Mô hình các kiểu dữ liệu trong trò chơi ........................................ 57
Hình 3.4: Giao diện chính của trò chơi .......................................................... 60
Hình 3.5: Văn bản hƣớng dẫn trò chơi .......................................................... 61
Hình 3.6: Giao diện trò chơi khi kết thúc ...................................................... 62
Hình 3.7: Giao diện Degbug chƣơng trình .................................................... 70

7


MỞ ĐẦU
Lý do chọn đề tài
Ngày nay Internet kết nối hàng tỷ ngƣời trên khắp thế giới và ứng dụng phổ
biến nhƣ các mạng xã hội, công cụ tìm kiếm, các dịch vụ blog cá nhân… đƣợc sử
dụng bởi hàng triệu hoặc thậm chí hàng tỷ ngƣời sử dụng trên máy tính. Điều này
thể hiện một sự thay đổi cả về phạm vi và quy mô của những gì chúng ta mong đợi
về máy tính có thể làm cho con ngƣời. Với lợi ích của các ứng dụng web hiện đại

và các ứng dụng trên di động đều có tính tƣơng tác cao với vô số các sự kiện liên
quan đến tƣơng tác của ngƣời dùng. Các ứng dụng ngày càng phát triển và phong
phú cho phép tƣơng tác cao với ngƣời sử dụng ở thời gian thực. Để làm đƣợc điều
đó chúng ta cần phải nghiên cứu và thiết kế những ứng dụng phổ biến để thực hiện
những kỹ thuật này.
Điều đầu tiên là khi chúng ta cung cấp cho một máy tính một nhiệm vụ
chúng ta muốn nó phản ứng lại nhanh nhất có thể. Nói một cách khác các máy tính
phải phản ứng với ngƣời sử dụng của nó và đáp ứng đƣợc các yêu cầu một cách
chính xác. Ví dụ khi chúng ta gửi một email thông qua Gmail bạn muốn xác nhận
rằng nó đã đƣợc gửi đi hoặc khi ta xóa một email thì nó sẽ biến mất khỏi danh sách
hiển thị, tất cả những thao tác ngƣời sử dụng đều đƣợc hiển thị bởi các trình duyệt
web. Hoặc khi chúng ta chơi một trò chơi thì các tƣơng tác của chúng ta với các
nhân vật trong trò chơi phải đƣợc phản ứng theo ý của chúng ta trong một thời gian
nhất định để có thể đạt mục đích. Để có thể làm đƣợc những điều này thì lập trình
phản ứng là một câu trả lời.
Lập trình phản ứng là sự kết hợp của hệ thống đồng thời và hệ thống hƣớng
sự kiện và cho phép xử lý luồng dữ liệu không đồng bộ nhƣng vẫn duy trì phong
cách của những ngôn ngữ lập trình thông thƣờng.
Lập trình phản ứng làm tăng mức độ trừu tƣợng mã giúp ngƣời lập trình tập
trung vào các sự kiện có liên quan tới nhau giải quyết những logic phức tạp. Mã
8


trong lập trình phản ứng thƣờng ngắn gọn, rõ dàng và dễ duy trì hơn. Tƣ duy trong
lập trình phản ứng thƣờng thiên về việc truyển đổi từ các dữ liệu đầu vào tƣơng tác
với dữ liệu trong chƣơng trình để hiện thị dữ liệu đầu ra.
Ở trên thế giới hiện nay lập trình phản ứng là một xu hƣớng mới nổi đƣợc
dựa trên luồng chảy dữ liệu (dataflow) và giá trị của chúng sẽ đƣợc thay đổi một
cách tự động nếu nhƣ có sự tác động từ môi trƣờng bên ngoài vào. Với sự phổ biến
của hƣớng sự kiện, khả năng mở rộng và các kiến trúc tƣơng tác trên cả máy chủ và

máy trạm các khái niệm về "reactiveness" đang ngày càng đƣợc chú ý. Nó ứng
dụng rất cao để viết các ứng dụng web hoặc các hệ thống liên quan tới cơ sở dữ liệu
lớn và cũng là phƣơng pháp tạo ra nhiều hệ thống đồng thời có tính hiệu quả cao.
Mục đích nghiên cứu
Mục đích nghiên cứu trong luận văn nhằm tìm hiểu các đặc điểm của lập
trình phản ứng, cụ thể ở đây là nghiên cứu về lập trình phản ứng trong ngôn ngữ
Elm, một ngôn ngữ khá mới trên thế giới và đang trong quá trình phát triển. Từ đó
nắm vững đƣợc các đặc điểm của lập trình phản ứng cũng nhƣ cách vận dụng
chúng trong ngôn ngữ Elm để tạo ra các ứng dụng mang tích tƣơng tác với ngƣời
sử dụng có tính hiệu quả cao. Mục đích thứ 2 là hiểu rõ đƣợc các cú pháp cũng nhƣ
phƣơng thức hoạt động động của ngôn ngữ Elm từ đó áp dụng vào để xây dựng lên
một chƣơng trình cụ thể.
Đối tƣợng và phạm vi nghiên cứu
Đầu tiên ta sẽ nghiên cứu các đặc điểm và phƣơng thức hoạt động của lập
trình phản ứng xem chúng có điểm tƣơng đồng gì với luồng dữ liệu. Tiếp theo tôi
tập chung nghiên cứu sâu về ngôn ngữ Elm để làm nổi bật đƣợc các đặc điểm của
lập trình phản ứng. Ngôn ngữ Elm là một ngôn ngữ mới đƣợc phát triển nó hoạt
động dựa trên các thao tác với các giá trị đầu vào cái đƣợc gọi là tín hiệu (Signal).
Tín hiệu là các giá trị dòng chảy thay đổi theo thời gian và nó đƣợc thiết lập và xử
9


lý để thay đổi các giá trị luồng dữ liệu trong chƣơng trình. Các thƣ viện trong Elm
cũng khá là đơn giản và đầy đủ cho phép tối ƣu hóa mã lập trình và tạo giao diện
tƣơng tác ngƣời dùng một cách dễ dàng. Elm là hoàn toàn hƣớng sự kiện và việc
tính toán lại giá trị chỉ trừ khi một sự kiện xảy ra và nó hỗ trợ việc xử lý các luồng
dữ liệu không đồng bộ. Cuối cùng tôi sẽ xây đựng một trò chơi bằng ngôn ngữ Elm
để thể hiện rõ đƣợc đặc điểm của lập trình phản ứng trong đó.
Kết cấu của luận văn
Luận văn của tôi trình bày ngoài phần mở đầu, mục lục, danh mục tài liệu

tham khảo, kết quả đạt đƣợc thì nội dung của luận văn gồm 3 chƣơng. Chƣơng 1 sẽ
nghiên cứu về lập trình phản ứng, nội dung trong chƣơng sẽ nêu ra những đặc điểm
về lập trình phản ứng, đặc điểm về luồng dữ liệu và xem chúng có những đặc điểm
gì tƣơng đồng hay không. Chƣơng 2 tôi sẽ nghiên cứu đôi nét về lập trình hàm từ
đó đi sâu về các cú pháp cơ bản của ngôn ngữ lập trình hàm Elm và cách tạo các
giao diện đồ họa và tìm hiểu các tín hiệu đầu vào tƣơng tác với chƣơng trình. Sau
đó tôi sẽ đi sâu vào cơ chế vận hành của ngôn ngữ Elm với các tín hiệu để thấy rõ
đƣợc điểm mạnh của của lập trình hàm phản ứng. Cũng trong chƣơng này ta nghiên
cứu về trình gỡ lỗi và lập trình tƣơng tác trong Elm. Chƣơng 3 sẽ áp dụng ngôn ngữ
Elm vào để xây dựng một trò chơi nhỏ thể hiện rõ các đặc điểm của lập trình hàm
phản ứng. Qua ứng dụng trò chơi cũng nhƣ các nghiên cứu thì luận văn tôi sẽ đƣa
ra một số nhận xét, đánh giá, thảo luận về ƣu nhƣợc điểm của lập trình phản ứng
trong chƣơng này. Nhờ những đánh giá này mà các nhà nghiên cứu và ngƣời lập
trình có thể tiếp tục phát triển ngôn ngữ Elm dùng nó làm công cụ để tạo ra các ứng
dụng mang tính tƣơng tác cao với ngƣời sử dụng.

10


CHƢƠNG 1-GIỚI THIỆU VỀ LẬP TRÌNH PHẢN ỨNG
1.1 Giới thiệu lập trình phản ứng
Lập trình phản ứng là một mô hình lập trình tập trung vào các luồng (flow)
dữ liệu và sự lan truyền thay đổi của dữ liệu. Điều này có nghĩa chúng ta có thể
biểu diễn các dòng dữ liệu tĩnh hoặc động trong ngôn ngữ lập trình và mô hình lập
trình sẽ tự động lan truyền các thay đổi thông qua luồng dữ liệu này. [13]
Ví dụ trong lập trình truyền thống (imperative programming) a:= b + c sẽ
có nghĩa là gán các kết quả b + c cho a. Sau đó nếu ta gán cho b và c giá trị khác,
thì giá trị của a không thay đổi theo. Nhƣng trong lập trình phản ứng giá trị a sẽ tự
động cập nhật khi chúng ta thay đổi giá trị của b hoặc c. Hay nhƣ một chƣơng trình
bảng tính Excel là một ví dụ về lập trình phản ứng. Ví dụ ô (cell) A1 chứa công

thức “=B1+C1”, thì giá trị của ô A1 này thay đổi khi chúng ta thay đổi giá trị ở ô
B1 hoặc C1.
Lập trình phản ứng chính cho phép ngƣời lập trình dễ dàng tạo ra các giao
diện ngƣời dùng tƣơng tác, hình ảnh động cho các hệ thống thời gian thực, nhƣng
vẫn tuân theo mô hình lập trình thông dụng. Ví dụ trong kiến trúc MVC (ModelView-Controller) với lập trình phản ứng, chúng ta chỉ cần thay đổi mô hình thì giao
diện sẽ tự động đƣợc cập nhật và ngƣợc lại khi ngƣời dùng thay đổi giá trị trên giao
diện, thì giá trị đó cũng đƣợc tự động cập nhật trên mô hình.
Ngôn ngữ lập trình phản ứng có thể thay đổi rất rõ ràng nơi mà các luồng dữ
liệu đƣợc thiết lập bằng cách sử dụng các cấu trúc lập trình hàm có trong thƣ viện,
ở đó các luồng dữ liệu đƣợc xây dựng từ các cấu trúc ngôn ngữ giống nhƣ lập trình
truyền thống hay lập trình hàm.
Ví dụ lập trình hàm phản ứng (functional reactive programming) là mô hình
lập trình hàm với phong cách lập trình phản ứng đƣợc thực thi bởi một nút trong
một đồ thị luồng dữ liệu đã đƣợc cấu trúc. Thƣ viện lập trình phản ứng dành cho
các ngôn ngữ khá linh động cho phép xây dựng các nút để xử lý một sự kiện nào đó
11


từ bên ngoài dựa vào thời gian thực thi chƣơng trình để cập nhật giá trị luồng dữ
liệu. Các nút trong đồ thị luồng dữ liệu là nơi mà chƣơng trình trao đổi thông tin
với nhau.
Lập trình phản ứng có thể hoàn toàn tĩnh nơi các luồng dữ liệu đƣợc thiết lập
tĩnh hoặc là động nơi các dòng dữ liệu có thể thay đổi trong quá trình thực hiện
chƣơng trình. Việc trao đổi dữ liệu trong đồ thị dòng dữ liệu tới phạm vi nào đó có
thể làm dòng dữ liệu tĩnh trở thành động và có thể cấu trúc lại đồ thị dòng dữ liệu.
Lập trình phản ứng có thể đƣợc gọi là bậc cao nếu trong chƣơng trình các
luồng dữ liệu có thể tạo ra các luồng dữ liệu khác dẫn tới kết quả đầu ra của một
luồng dữ liệu là một đồ thị luồng dữ liệu khác và cũng đƣợc thực hiện bằng các mô
hình đánh giá nhƣ lúc đầu.
Trong lập trình phản ứng các tính toán thƣờng đƣợc lƣu trữ trong bộ nhớ và

ở dạng dữ liệu cấu trúc. Khi một vài dữ liệu trong chƣơng trình thay đổi sẽ làm
thay đổi toàn bộ dữ liệu có liên quan thay đổi theo, việc cập nhật dữ liệu có thể có
nhiều cách nhƣng thông thƣờng nhất vẫn là giá trị đƣợc lƣu trữ lại và đƣợc gọi khi
cần.
Lập trình phản ứng có nhiều điểm giống với các mô hình thiết kế phần mềm
chung thƣờng đƣợc sử dụng trong lập trình hƣớng đối tƣợng. Tuy nhiên việc tích
hợp các khái niệm luồng dữ liệu vào các ngôn ngữ lập trình sẽ làm cho nó dễ dàng
hơn để thể hiện chúng và làm tăng mức chi tiết của biểu đồ luồng dữ liệu.
Về cơ bản trong lập trình phản ứng luôn thể hiện đƣợc dữ liệu nhƣ là “giá trị
thay đổi theo thời gian” chúng có thể đƣợc kết hợp, lọc, nối và chuyển đổi để cập
nhật giá trị mới nhất. Lập trình phản ứng luôn mang tính hƣớng sự kiện và dữ liệu
đƣợc mô hình thành các tín hiệu chứa giá trị hiện tại, thay đổi một cách rời rạc gọi
là sự kiện. Các sự kiện này trên thực thực tế là một dòng sự kiện bất đồng bộ, hay
cũng có thể nói lập trình phản ứng là lập trình với dòng dữ liệu bất đồng bộ.

12


1.2 Lập trình phản ứng là luồng dữ liệu
Lập trình phản ứng là một thuật ngữ đã trở nên phổ biến gần đây và nguồn
gốc của nó xuất hiện là năm 1985. Trên bài báo“On the Development of Reactive
Systems” đƣợc viết bởi (David Harel & Amir Pnueli, 1985) đã đƣợc định nghĩa về
hệ thống phản ứng (reactive systems):
“Các hệ phản ứng… là đƣợc lặp đi lặp lại ngay tức thời bởi các yếu tố bên
ngoài và vai trò của chúng là đáp ứng liên tục với các dữ liệu đầu vào từ bên
ngoài.”[7]
Một vài năm sau đó vào năm 1989 trong bài báo “Real Time Programming:
Special Purpose or General Purpose Languages” của (Gerard Berry, 1989) đã tập
trung vào khía cạnh phần mềm:
“ Hệ phản ứng là điểm thuận lợi để phân biệt giữa ba loại chƣơng trình máy

tính. Chƣơng trình trao đổi thông tin tính toán từ một tập hợp các yếu tố đầu vào;
ví dụ điển hình là các trình biên dịch hoặc các chƣơng trình tính toán số. Các
chƣơng trình tƣơng tác tƣơng tác phản ứng ở tốc độ của riêng của chúng với
ngƣời dùng hoặc với các chƣơng trình khác. Các chƣơng trình phản ứng cũng
duy trì tính tƣơng tác liên tục với môi trƣờng của chúng và đƣợc quyết định bởi
môi trƣờng. Các chƣơng trình tƣơng tác làm việc ở tốc độ của riêng chúng và chủ
yếu là đối phó với các thông tin liên lạc, trong khi đó chƣơng trình phản ứng chỉ
làm việc để đáp ứng với nhu cầu bên ngoài và chủ yếu là xử lý chính xác các sự sự
kiện diễn ra.” [8]
Vì vậy ta có thể nói rằng lập trình phản ứng gồm các yếu tố sau: [2]
 Xử lý đáp ứng các yêu cầu bên ngoài.
 Chủ yếu là xử lý song song các luồng dữ liệu.
 Điều chỉnh thay đổi phù hợp với dữ liệu đầu vào.
 Dùng để thực hiện các vấn đề liên quan đến tính tƣơng tác và thƣờng xuyên
thay đổi thông tin.
13


Chúng ta cùng tìm hiểu khái niệm luồng dữ liệu là khi dữ liệu điều khiển
thực thi chƣơng trình và kiểm tra các dữ liệu đầu vào sau đó phản ứng với sự thay
đổi dữ liệu, cập nhật bất cứ khi nào dữ liệu mới đến. Bất kỳ hệ thống nào mà ở đó
dữ liệu di chuyển giữa các đơn vị mã và đƣợc kích hoạt thực thi chúng có thể đƣợc
gọi là luồng dữ liệu trong đó bao gồm các hệ thống phản ứng. Vì vậy ta xem xét lập
trình phản ứng là một tập hợp con của luồng dữ liệu nhƣng là một nhóm khá lớn.
Trong trƣờng hợp bình thƣờng lập trình phản ứng đƣợc coi nhƣ là một từ đồng
nghĩa với luồng dữ liệu. [2]
Luồng dữ liệu nhƣ là một mô hình kết nối giữa các đối tƣợng trong một ứng
dụng, trong chƣơng trình nó sẽ phản ứng một cách khá hiệu quả với những thay đổi
dữ liệu đầu vào từ môi trƣờng bên ngoài vào. Các nhà nghiên cứu đã tìm hiểu và
phát triển những cái lợi thế của các ràng buộc của luồng dữ liệu bằng việc nhúng

luồng dữ liệu vào các ngôn ngữ lập trình nhằm xử lý các ràng buộc giữa các giá trị
của các đối tƣợng dựa trên các sự kiện tác động bên ngoài cái mà chúng ta thƣờng
gọi là phản ứng. Với phƣơng pháp này các đối tƣợng sẽ đƣợc khai báo nhƣ các kiểu
dữ liệu căn bản, dữ liểu mảng, con trỏ hay dữ liệu cấu trúc và việc định nghĩa ràng
buộc các câu lệnh sẽ tự động tái xử lý các đầu vào thay đổi trong bộ nhớ làm cho
chƣơng trình chúng ta hoạt động nhƣ một bảng tính mà các giá trị của biến này phụ
thuộc vào biến kia.
Một số tính năng của dòng dữ liệu:
 Dataflow có khả năng quản lý song song các luồng dữ liệu.
 Dataflow là đáp ứng với sự thay đổi dữ liệu thông qua các sự kiện. Giá trị
truyền vào thay đổi thì dòng dữ liệu thay đổi theo.
 Dataflow nhƣ sự thay thế cho phƣơng pháp “callback hell”.
 Dataflow nhƣ một đồ thị chứa tập các nút và khi dữ liệu đến nó sẽ đƣợc xử lý
và thực thi một nhiệm vụ nào đó nếu đƣợc yêu cầu từ bên ngoài.

14


Lập trình phản ứng đƣợc coi là lập trình với các dòng dữ liệu không đồng bộ.
Các sự kiện trong dòng có thể xảy ra bất cứ lúc nào và không cần phải xảy ra theo
một trình tự thông thƣờng điển hình là các sự kiện nhấp chuột hoặc di chuột là là
một dòng sự kiện không đồng bộ, giá trị của chúng luôn đƣợc cập nhật mà không
phải đợi thời gian tính toán lâu dài của một sự kiện khác trong chƣơng trình.
Phản ứng là ý tƣởng của việc tự sinh (steroids) [12] nên chúng ta có thể tạo
ra các dòng dữ liệu từ các biến, dữ liệu ngƣời dùng nhập vào, các bộ nhớ đệm, các
cấu trúc dữ liệu…bằng những tín hiệu tác động từ môi trƣờng bên ngoài vào làm
thay đổi giá trị của chƣơng trình. Một dòng dữ liệu là một chuỗi các sự kiện diễn ra
trong một thời gian.
Để hiểu rõ hơn về dòng dữ liệu trong lập trình phản ứng ta xét một số ví dụ
sau:

Ví dụ 1: Tạo ra một dòng sự kiện nhấp chuột với mỗi lần click chuột sẽ in ra
tổng số lần nhấp chuột.
1
2
3
4
5
7
8
9

import Graphics.Element exposing (..)
import Mouse
main : Signal Element
main=
Signal.map show countClick
countClick : Signal Int
countClick=
Signal.foldp (\clk count -> count +1)0 Mouse.clicks

Dòng dữ liệu ở ví dụ trên chính là tín hiệu click chuột (Mouse.clicks) cứ
mỗi lần nhấp chuột dòng dữ liệu sẽ thay đổi thể hiện qua hàm countClick. Hàm
này sẽ thể hiện đƣợc khi ngƣời dùng nhấp chuột một lần thì tổng số lần nhấp chuột
sẽ tăng lên. Hàm main sẽ sử dụng hàm Signal.map để chuyển hàm countClick từ
kiểu Int sang kiểu thành phần (Element) khi đó giá trị sẽ đƣợc hiển thị trên màn
hình.
Ví dụ 2: Trong ví dụ này dòng dữ liệu sẽ thay đổi giá trị khi tín hiệu chuột
thay đổi. Xét đoạn mã trong ngôn ngữ Elm dƣới đây :
15



1 import Color exposing (..)
2 import Graphics.Collage exposing (..)
3 import Graphics.Element exposing (..)
4 import Signal exposing (Signal, map, map2)
5 import Mouse
6 import Window
7 scene (w,h) (x,y) =
8
collage w h
9
[ filled red (circle 30)
10
, rotate (degrees(toFloat y)) (scale (toFloat x/100) (outlined
(solid blue) (rect 50 50)))
11
, rotate (degrees 30) (toForm (show "hello"))
12
]
13 main = map2 scene Window.dimensions Mouse.position

Hàm main ở trên sẽ thực thi chƣơng trình và thông số của cửa sổ trình duyệt
và thông số chuột đƣợc truyền vào hàm scene. Hàm collage nhƣ một tập hợp các
dòng thành phần: Dòng thành phần thứ nhất là hình tròn bán kính 30, dòng thứ 2 là
sự kiện quay theo trục y và kéo giãn tự động theo trục x của hình vuông, dòng thứ 3
là dòng text "hello" nghiêng 30 độ và tất cả chúng hợp chung thành một hàm dòng
chảy. Các tín hiệu đƣợc kết hợp chuyển đổi giá trị thông qua hàm map2. Khi sự kiện
di chuột diễn ra thì kích cỡ hình vuông sẽ tự động co giãn và xoay theo hƣớng
chúng ta di chuột.


Hình 1.1: Sự truyển đổi giá trị liên tục của dòng theo tín hiệu
chuột

16


1.3 Đặc điểm của lập trình phản ứng
Lập trình phản ứng có những đặc điểm sau: [15,16,17]
 React to events: Phản ứng hƣớng sự kiện là mô hình lập trình dựa trên các sự
kiện đầu vào hoặc các thông điệp (message) từ bên ngoài. Do đó ngƣời lập
trình có thể viết sẵn các hàm xử lý sự kiện có thể xảy ra khi ngƣời dùng
tƣơng tác. Thay vì phải chờ chƣơng trình xử lý thì ngƣợc lại chƣơng trình
chờ tƣơng tác của ngƣời dùng có nghĩa là hệ thống sẽ phản ứng ngay lập tức
khi có sự kiện xảy ra.
 React to load: Là một ứng dụng có khả năng mở rộng theo cách sử dụng của
nó. Chúng ta có thể xây dựng lên các hệ thống đồng thời xử lý song song
nhiều luồng dữ liệu cùng một lúc và tạo ra khả năng cập nhật các sự xảy ra
cùng một thời điểm hay chính là tạo ra cơ chế đồng bộ hóa cho mỗi dòng để
duy trì thứ tự các sự kiện trong lập trình phản ứng.
 React to failure: Khả năng nắm bắt và phục hồi lỗi. Trong lập trình phản ứng
các sự kiện đƣợc gắn liền với thời gian và khi chúng ta di chuyển thời gian
chạy trạng thái sẽ đƣợc lƣu trữ. Các sự kiện đầu vào điểu khiển trạng thái
thay đổi khi chƣơng trình chạy và chúng đƣợc ghi lại nhƣ những bản ghi.
Một hệ thống có khả năng tìm và xử lý chính xác các bản ghi bị lỗi là một hệ
thống tốt, tiêu biểu là công cụ “Time Traveling Debugger” trong ngôn ngữ
Elm đƣợc đề cập ở phần 2.6 của luận văn.
 React to users: Phản ứng với các tƣơng tác ngƣời dùng có nghĩa là xây dựng
một ứng dụng có thể đáp ứng nhanh chóng với tất cả các tác động bên ngoài
vào. Tính chất này đƣợc xây dựng trên một kiến trúc tổng thể của cả ba yếu
tố hƣớng sự kiện, khả năng mở rộng hệ thống và khả năng phục hồi lỗi.

Với các đặc điểm của lập trình phản ứng ta có thể xây dựng một hệ thống
phản ứng linh hoạt hơn, giảm tính lỏng lẻo (loosely-coupled) và khả năng mở rộng
và hƣớng sự kiện. Điều này làm cho chúng dễ dàng hơn để phát triển và thay đổi
17


chƣơng trình. Hệ thống phản ứng là đáp ứng tất cả tính năng trên đem lại cho ngƣời
sử dụng tính phản hồi tƣơng tác hiệu quả. Sau đây là các tính chất nổi bật của một
hệ thống phản ứng: [14]
Responsive (reactor user): Hệ thống phản hồi một cách kịp thời nếu có thể.
Phản hồi của hệ thống là tập trung vào việc cung cấp thời gian đáp ứng nhanh
chóng và phù hợp, đáp ứng đƣợc với các sự kiện ngƣời dùng tác động vào với một
giới hạn thời gian đƣợc ấn định.
Resilient (reactor failure): Khả năng tìm và phục hồi lỗi trong hệ thống một
cách nhanh chóng. Các lỗi thƣờng đƣợc chứa trong mỗi thành phần do đó khi xử lý
và phục hồi thƣờng không ảnh hƣởng tới toàn bộ hệ thống.
Saclable (reactor load): Hệ thống có khả năng mở rộng và đáp ứng khối
lƣợng công việc khác nhau. Hệ thống phản ứng có thể phản ứng với những thay đổi
dựa vào tỷ lệ đầu vào.
Message Driven (reactor events): Hệ thống phản ứng dựa vào việc truyền tải
thông điệp không đồng bộ để thiết lập một ranh giới giữa các dòng dữ liệu đảm bảo
giảm tính lỏng lẻo, việc cách ly, vị trí minh bạch và cung cấp các biện pháp xử lý
lỗi của thông điệp. Làm rõ ràng thông điệp truyền đi cho phép lƣu trữ trạng thái và
kiểm soát dòng chảy một cách mềm dẻo bằng cách sắp xếp, giám sát hàng đợi tin
nhắn trong hệ thống và gọi lại khi cần thiết.

Hình 1.2: Sơ đồ các đặc điểm của lập trình phản ứng
18



1.4 Lập trình hàm phản ứng
Lập trình hàm phản ứng (Functional Reactive Programming) là mô hình lập
trình hàm làm việc với các giá trị thay đổi. FRP tính toán lại với các giá trị thay đổi
khi giá trị thời gian thay đổi. Giá trị thời gian khác nhau đƣợc gọi là tín hiệu
(signal). Tín hiệu có thể đại diện cho các giá trị thay đổi. Ví dụ xem xét vị trí trỏ
chuột khi chuột di chuyển giá trị của Mouse.position thay đổi tự động. Tín hiệu có
thể đƣợc chuyển đổi và kết hợp.
Các khái niệm chính của lập trình hàm phản ứng là các tín hiệu hoặc các
hành vi là giá trị tại các thời điểm và các sự kiện kết nối các giá trị thay thế hoặc
giá trị tại thời điểm đó.
Sự kiện bao gồm một chuỗi các giá trị rời rạc theo thời gian nhƣ nhấp chuột,
gõ phím hoặc từ một kết nối web server (websocket) tạo ra. Khái niệm về sự kiện
này thƣờng đƣợc biểu diễn nhƣ một dòng. Ở giữa các giá trị rời rạc, sự kiện sẽ
không có giá trị nào đƣợc thiết lập. Khi một sự kiện xảy ra tại một thời gian thì giá
trị nhất định đƣợc thiết lập.
Chúng ta cùng xem xét 3 mô hình của lập trình hàm ứng: Classical FRP;
Real-time FRP & Event-Driven FRP; Và Arrowized FRP.
1.4.1 Classical FRP
Lập trình hàm phản ứng ban đầu đƣợc xây dựng bởi (Paul Hudak & Conal
Elliott, 1997) trên cuốn sách của họ “Functional Animation Reactive” [9]. Việc
thực hiện chúng đƣợc nhúng vào ngôn ngữ Haskell, một ngôn ngữ lập trình hàm và
dễ dàng đƣợc mở rộng. Công thức ban đầu của lập trình hàm phản ứng cái mà đƣợc
gọi là Classical FRP đƣợc giới thiệu với 2 kiểu giá trị mới: Các hành vi (Behaviors)
và các sự kiện (Events).
Các hành vi thì luôn liên tục và giá trị thay đổi theo thời gian. Điều này đƣợc
thể hiện khi một hàm ở một thời điểm sẽ có một giá trị.
Behavior α = Time -> α

19



Các hàm chuyển động theo thời gian cũng tƣơng đƣơng nhƣ các phƣơng
trình chuyển động trong vật lý học Newton. Ở thời điểm t hành vi có giá trị v và
thực hiện các nhiệm vụ phổ biến nhƣ mô hình hóa các hiện tƣợng vật lý: Tín hiệu
vị trí, vận tốc, gia tốc …
Các sự kiện đại diện cho một chuỗi các sự kiện rời rạc gắn với một danh sách
các giá trị tại mỗi thời điểm. Các giá trị theo thời gian luôn liên tục xuất hiện ở hầu
hết các công việc tiếp theo.
Event

α = [(Time, α )]

Fran (functional reactive animation) thừa hƣởng khá nhiều từ ngôn ngữ
chính của nó Haskell. Trong lập trình hàm phản ứng giá trị hành vi đƣợc kiểm tra
thƣờng xuyên vì vậy một tích lũy tính toán sẽ diễn ra trong một thời gian dài và
điều này sẽ tiếp tục dẫn đến việc thiếu bộ nhớ (space leak). Khi kiểm tra toàn bộ
việc tích lũy tính toán phải đƣợc đánh giá cùng một lúc sẽ gây ra một sự chậm trễ
về thời gian (time leak) hay kết quả tính toán trong một thời gian dài. [6]
Ngoài vấn đề bộ nhớ và thời gian tính toán classical FRP cho phép định
nghĩa các hành vi phụ thuộc vào quá khứ, hiện tại và giá trị tƣơng lai. Tức là các
chƣơng trình tạo giá trị mới từ các giá trị cũ. Việc dựa trên những giá trị quá khứ có
thể tăng bộ nhớ cái mà chƣơng trình bắt buộc nhớ các giá trị trong quá khứ của
hành vi hoặc sự kiện. Có nghĩa là sử dụng bộ nhớ tăng tỷ lệ thuận với thời gian mà
chƣơng trình chạy.
1.4.2 Real-time FRP & Event-Driven FRP
Real-time FRP đã đƣợc giới thiệu bởi Paul Hudak và những ngƣời khác tại
Yale trong năm 2001. Mục đích là giải quyết những thiếu sót của FRP classical.
Tạo ra một sự tƣơng đồng giữa các hành vi và các sự kiện. [6]
Event


α

Behavior

or (Maybe α)

Maybe α là một kiểu dữ liệu đƣợc trừu tƣợng hóa tức là nếu một sự kiện
xảy ra thì dữ liệu đầu vào sẽ thay đổi luồng dữ liệu trong chƣơng trình hoặc nếu
20


không có sự kiện xảy ra thì sẽ không có sự thay đổi gì cả. Cả các hành vi và các sự
kiện có thể đƣợc biểu diễn nhƣ một loại chung đó là tín hiệu.
Signal

α = Time -> α

Event – drivent FRP (E-FRP) giới thiệu về các tín hiệu rời rạc, tín hiệu mà
chỉ thay đổi khi sự kiện xảy ra. Nó mang tính hƣớng sự kiện trong đó không có sự
thay đổi nào đƣợc cập nhật trừ khi một sự kiện đƣợc xảy ra.
1.4.3 Arrowized FRP
Arrowized FRP đƣợc hình thành ở Yale vào năm 2002 bởi Henrik Nilsson,
Antony Courtney và John Peterson. Arrowized FRP (AFRP) sử dụng các hàm tín
hiệu. Một hàm tín hiệu có thể đƣợc coi nhƣ một hàm từ tín hiệu này tới tín hiệu
khác.
SF

α β

= Signal


α ->

Signal β

Ở đó các tính hiệu đƣợc xác định nhƣ là thời gian thực của lập trình hàm
phản ứng.
Signal

α = Time -> α

Để tránh việc tránh việc chậm chễ thời gian và thiếu bộ nhớ ngƣời lập trình
sẽ trực tiếp định nghĩa các tín hiệu tín hiệu đầu vào. Tín hiệu đầu vào là rời rạc và
mang tính hƣớng sự kiện, khi chúng tác động vào dòng dữ liệu việc tính toán lại chỉ
xảy ra khi có sự kiện sảy ra. Việc chậm chễ thời gian do quá trình xử lý tính toán
lâu dài của một phản ứng dẫn đến việc cập nhật của toàn bộ chƣơng trình phải đợi
theo cho đến khi quá trình xử lý xong một cách tuần tự. Mỗi tín hiệu tác động vào
dòng dữ liệu chúng có thể đƣợc xử lý song song với với các dòng dữ liệu khác mà
không phải đợi quá trình cập nhật chung. Xét đoạn mã sau đây:
input : Signal Input
input = Signal.sampleOn delta
<|(Signal.map5 Input
Keyboard.space
Keyboard.enter
Keyboard.arrows

21


Keyboard.wasd

delta)
main = Signal.map2 view Window.dimensions (Signal.foldp update
defaultGame input)

Ở đoạn mã trên ngƣời lập trình sử dụng hàm map5 tức là có 5 tín hiệu đầu
vào đƣợc sử dụng. Nếu một trong các tín hiệu tác động vào chƣơng trình thì nó sẽ
đƣợc cập nhật nếu xảy ra phản ứng giữa các đối tƣợng khi đó dữ liệu mặc định của
chƣơng trình (defaultGame) sẽ thay đổi. Còn nếu nhƣ không có phản ứng xảy ra thì
sẽ không có tính toán nào đƣợc xảy và bộ nhớ không phải lƣu trữ thêm giá trị gì.
Arrowized FRP linh hoạt hơn classical function với việc liên tục chuyển các
kết nối trong các hàm tín hiệu, cho phép các hàm tín hiệu an toàn và di chuyển
xung quanh thời gian chạy. Arrowized FRP thừa hƣởng tính liên tục của các tín
hiệu từ classical FRP. Trong khi đó Classical FRP vẫn bị mô hình chính phối.
Sự chậm trễ toàn cục là do việc tính toán lâu dài. Tất cả các hệ thống lập
trình hàm đều phải thực hiện nghiêm ngặt thứ tự các sự kiện. Các sự kiện đƣợc xử
lý tại một thời điểm nó xảy ra. Việc cập nhật trong một thời gian dài sẽ chặn tất cả
các sự kiện đang chờ dẫn đến làm chậm toàn bộ chƣơng trình.
Ngôn ngữ Elm sử dụng mô hình này và trách đƣợc 2 nhƣợc điểm là chậm trễ
toàn cục và thiếu bộ nhớ. Ta sẽ tìm hiểu kỹ hơn về cơ chế lập trình hàm phản ứng
trong ngôn ngữ Elm trong chƣơng 2.

22


CHƢƠNG 2 – LẬP TRÌNH PHẢN ỨNG VỚI NGÔN NGỮ ELM
Ở trong chƣơng này đầu tiên tôi sẽ khái quát chung về lập trình hàm vì ngôn
ngữ Elm là một ngôn ngữ lập trình hàm. Tiếp theo tôi đƣa ra một số cú pháp cơ bản
và một số ví dụ về việc tạo giao diện ngƣời dùng và miêu tả các tín hiệu đầu vào
trong Elm. Sau đó tôi tiếp tục đi sâu vào cơ chế hoạt động của ngôn ngữ Elm trong
lập trình phản ứng để thấy đƣợc cách hoạt động của các tín hiệu, các ƣu điểm nổi

bật của ngôn ngữ lập trình hàm phản ứng.
2.1 Khái quát về ngôn ngữ lập trình hàm
2.1.1 Định nghĩa
Lập trình hàm là phong cách lập trình dựa trên định nghĩa hàm sử dụng phép
tính lambda (X-calculus). Lập trình hàm không sử dụng các lệnh gán biến và không
gây ra hiệu ứng phụ nhƣ vẫn gặp trong lập trình mệnh lệnh. Trong các ngôn ngữ
lập trình hàm, hàm (thủ tục, chƣơng trình con) đóng vai trò trung tâm, thay vì thực
hiện lệnh, máy tính tính biểu thức. Đã có rất nhiều ngôn ngữ hàm đƣợc phát triển
và ứng dụng nhƣ Miranda, Haskell, Elm, ML, các ngôn ngữ họ Lisp: Scheme,
Common Lisp...[1]
2.1.2 Tính khai báo của ngôn ngữ hàm
Các ngôn ngữ hàm là cũng các ngôn ngữ bậc cao, mang tính trừu tƣợng hơn
so với các ngôn ngữ mệnh lệnh.
Những ngƣời lập trình hàm thƣờng tránh sử dụng các biến toàn cục, trong
khi đó hầu hết những ngƣời lập trình mệnh lệnh đều phải sử dụng đến biến toàn
cục.
Khi lập trình với các ngôn ngữ hàm ngƣời lập trình phải định nghĩa các hàm
toán học dễ suy luận, dễ hiểu mà không cần quan tâm chúng đƣợc cài đặt nhƣ thế
nào trong máy.
23


Những ngƣời theo khuynh hƣớng lập trình hàm cho rằng các lệnh trong một
chƣơng trình viết bằng ngôn ngữ mệnh lệnh làm thay đổi trạng thái toàn cục là
hoàn toàn bất lợi. Bởi vì rất nhiều phần khác nhau của chƣơng trình (chẳng hạn các
hàm, các thủ tục) tác động không trực tiếp lên các biến và do vậy làm chƣơng trình
khó hiểu. Các thủ tục thƣờng đƣợc gọi sử dụng ở các phần khác nhau của chƣơng
trình nên rất khó xác định các biến bị thay đổi nhƣ thế nào sau lời gọi. Nhƣ vậy, sự
xuất hiện hiệu ứng phụ làm cản trở việc chứng minh tính đúng đắn (correctness
proof), cản trở tối ƣu hóa (optimization) và cản trở quá trình song song tự động

(automatic parrallelization) của chƣơng trình.
Một ngôn ngữ hàm hay ngôn ngữ áp dụng (applicative language) dựa trên
việc tính giá trị của biểu thức đƣợc xây dựng từ bên ngoài lời gọi hàm. Ở đây hàm
là một hàm toán học thuần túy: Là một ánh xạ nhận các giá trị lấy từ một miền xác
định (domain) để trả về các giá trị thuộc một miền khác (range hay co-domain).
Một hàm có thể có hoặc không có, các tham đối (arguments hay parameters)
để sau khi tính toán, hàm trả về một giá trị nào đó. Chẳng hạn có thể xem biểu thức
2 + 3 là hàm tính tổng (phép +) của hai tham đối là 2 và 3.
Vì vậy lập trình hàm không gây ra hiệu ứng phụ trong trạng thái của chƣơng
trình, nếu trạng thái này đƣợc duy trì cho các tham đối của hàm. Tính chất này
đóng vai trò trong lập trình hàm. Đó là kết quả của một hàm không phụ vào thời
điểm (when) hàm đƣợc gọi mà chỉ phụ thuộc vào cách gọi nó nhƣ thế nào đối với
các tham đối.
Với việc hàm không phụ thuộc nhiều vào các biến toàn cục nên việc lập trình
hàm sẽ dễ hiểu hơn lập trình mệnh lệnh.
Bên cạnh tính ƣu việt ta cũng cần xem xét những bất lợi vốn có của lập trình
hàm: Nhƣợc điểm của ngôn ngữ hàm là thiếu các lệnh gán và các biến toàn cục, sự
khó khăn trong việc mô tả các cấu trúc dữ liệu và khó thực hiện quá trình vào và ra
dữ liệu.
24


Tuy nhiên ta thấy rằng sự thiếu các lệnh gán và các 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 các biến đƣợc mô phỏng bằng cách sử dụng cơ cấu tham biến của các hàm,
ngay cả trong các chƣơng trình viết bằng ngôn ngữ mệnh lệnh.
Tóm lại ngôn ngữ hàm dựa trên việc tính giá trị của biểu thức. Các biến toàn
cục và phép gán bị loại bỏ, giá trị đƣợc tính bởi một hàm chỉ phụ thuộc vào các
tham đối. Thông tin trạng thái đƣợc đƣa ra tƣờng minh nhờ các tham đối của hàm
và kết quả.

2.1.3 Một số khái niệm cơ bản trong ngôn ngữ hàm
Khái niệm hàm
Hàm là khái niệm cơ bản trong các ngôn ngữ hàm. Một hàm có thể nhận từ
không đến nhiều tham đối vào để tính toán và trả về một giá trị, giá trị này chỉ phụ
thuộc vào các tham đối đã nhận mà thôi. [1]
Trong Elm một hàm đƣợc định nghĩa bởi hai phần: Phần khai báo và phần
định nghĩa hàm. Phần khai báo có thể vắng mặt có dạng một nguyên mẫu hàm:
<tên hàm> : <miền xác định> - > <miền giá trị>
Phần định nghĩa hàm có dạng một phƣơng trình, gồm vế trái và một số vế
phải, mỗi vế phải có thể có một điều kiện đóng vai trò «lính gác» (guard) phân biệt
đứng cuối:
<tên hàm> [ <danh sách tham đối> ] = <biểu thức> [ <điều kiện> ]
Đệ quy
Vòng lặp trong các ngôn ngữ hàm thƣờng đƣợc thực hiện thông qua đệ quy.
Hàm đệ quy sẽ tự gọi chính nó cho phép thực hiện đi thực hiện lại một tác vụ. Việc
đệ quy có thể đòi hỏi phải sử dụng một chồng (stack) nhƣng đệ quy đuôi vẫn có thể
đƣợc trình biên dịch nhận ra và tối ƣu hóa nó thành cùng đoạn mã đƣợc dùng để
hiện thực vòng lặp trong ngôn ngữ mệnh lệnh. Tiêu chuẩn của ngôn ngữ hàm là
25


×