Như vậy là chúng ta đã điểm qua các công cụ chính mà Ada
cung cấp ở cấp độ cú pháp của một ngôn ngữ đặt nền móng trọng tâm trên Procedural Programming
. Và so với C
thì thư viện tiêu chuẩn của Ada
cũng được triển khai rộng hơn và cung cấp cả những cấu trúc dữ liệu tập hợp như List
, Set
, Map
, v.v…
Tuy nhiên mục đích của mình khi bắt đầu tìm hiểu về ngôn ngữ Ada
và cho tới thời điểm này thì vẫn là để hiểu hơn về phương cách tư duy của kỹ sư thiết kế ngôn ngữ này – hay phương cách thiết kế và kiến trúc nên một phần mềm nào đó bằng ngôn ngữ Ada
với tư duy Procedural Programming
. Vì vậy nên việc viết một project
nhỏ là rất cần thiết để nghiệm thu lại những hiểu biết về ngôn ngữ Ada
và một trong số những mô hình lập trình phổ biến mà chúng ta đang tìm hiểu.
Procedural Thinking
Tư duy căn bản của Procedural Programming
hiển nhiên sẽ xoay quanh các sub-program
được gọi là procedure
mà chúng ta đã biết. Khác biệt căn bản giữa định nghĩa thủ tục procedure
và định nghĩa hàm function
được vay mượn từ toán học là:
@reflection
record A ---> function ---> new record Z
@effection
procedure ---> record A ---> modified record A
Các hàm function
là các công cụ mô tả logic ánh xạ và sẽ không tạo ra tác động thay đổi tới các dữ liệu trạng thái state
. Khi chúng ta có một record
ban đầu A
, được truyền vào một lời gọi hàm f (A)
thì ở đây hàm f
sẽ mô tả một logic chỉ đường tham chiếu tới một record
kết quả trả về mới Z
. Và bản ghi A
ban đầu sẽ không bị thay đổi về mặt nội dung.
Trong khi đó thì các procedure
lại không phải là các công cụ mô tả logic ánh xạ, mà thay vào đó lại có ý nghĩa mô tả các thao tác khách quan tác động lên các dữ liệu trạng thái state
. Khi chúng ta có một record A
, được truyền vào một lời gọi thủ tục p (A)
thì ở đây thủ tục p
sẽ thực hiện thao tác thay đổi nội dung của record A
ban đầu chứ không tạo ra một record Z
hoàn toàn mới như function
.
Như vậy, chúng ta có thể hình dung đơn giản là Procedural Programming
sẽ nhìn nhận một chương trình bất kỳ bao gồm 2 thành phần căn bản là:
procedure-that
|
|
|/
:
procedure-left ------> state <------ procedure-right
:
/|
|
|
procedure-this
- Các dữ liệu trạng thái
state
được lưu trữ cố định ở một điểm nào đó. Ví dụ: các biến toàn cụcglobal
, các biếnlocal
củaprocedure Main
, hoặc cũng có thể làstate
của các nguồn trừu tượng như trạng thái hiển thị của cửa sổ dòng lệnhconsole
. - Các
procedure
được thiết kế xoay quanhstate
để tạo ra các thao tác thay đổi nội dung củastate
đang lưu trữ.
Các hàm function
tuy cũng được sử dụng trong môi trường Procedural
, tuy nhiên chỉ đóng vai trò là các chức năng hỗ trợ utility
cho các thao tác tính toán, và sẽ được gọi bởi các procedure
chính điều khiển logic xử lý của phần mềm.
Init Project
Sau khi nhắc lại khái niệm căn bản về Procedural Programming
thì ở đây chúng ta sẽ bắt đầu khởi tạo project
để xây dựng một ứng dụng console
– tương tác với người dùng nhập liệu trên cửa sổ dòng lệnh.
cd Documents
alr init --bin console_tictactoe
Success: console_tictactoe initialized successfully.
Lúc này chúng ta đã có một thư mục project
với tên như mô tả trong lệnh khởi tạo phía trên và đã có thể chỉnh sửa code ở tệp khởi chạy để biên dịch thử.
with Ada.Text_IO; use Ada.Text_IO;
procedure Console_Tictactoe is
-- local
begin
Put_Line ("Console Tic-Tac-Toe");
end Console_Tictactoe;
cd console_tictactoe
alr run
Note: Building console_tictactoe/console_tictactoe.gpr...
Setup
[mkdir] object directory for project Console_Tictactoe
Compile
[Ada] main.adb
Bind
[gprbind] main.bexch
[Ada] main.ali
Link
[link] main.adb
Build finished successfully in 1.15 seconds.
Console Tic-Tac-Toe
Sau khi chạy lệnh alr run
lần đầu thì trong thư mục gốc của project
sẽ xuất hiện thêm một số thư mục được tạo ra do alr
và gprbuild
. Lúc này chúng ta có cấu trúc tổng quan của thư mục project
như thế này:
console-tictactoe
├── alire
│ ├── alire.lock
│ └── config.toml
├── alire.toml
├── bin
│ └── console_tictactoe.exe
├── config
│ ├── console_tictactoe_config.ads
│ ├── console_tictactoe_config.gpr
│ └── console_tictactoe_config.h
├── console_tictactoe.gpr
├── obj
│ ├── ...
│ └── console_tictactoe.o
├── share
└── src
└── console_tictactoe.adb
Ở đây chúng ta có thể thực hiện chỉnh sửa các tệp cấu hình của project
để điều khiển tiến trình biên dịch của gprbuild
và thay đổi tên của tệp khởi chạy thành main.adb
và procedure Main
.
with "config/console_tictactoe_config.gpr";
project Console_Tictactoe is
for Languages use ("Ada", "C");
for Create_Missing_Dirs use "True";
for Source_Dirs use ("src/**", "config");
for Object_Dir use "obj";
for Exec_Dir use "bin";
for Main use ("main.adb");
package Compiler is
for Default_Switches ("Ada") use ("-gnat2020", "-gnata");
end Compiler;
package Binder is
for Switches ("Ada") use ("-Es");
end Binder;
package Install is
for Artifacts (".") use ("share");
end Install;
end Console_Tictactoe;
- Danh sách các ngôn ngữ
Languages
có thể sử dụng trongproject
được khai báo cụ thể và nếu muốn thì bạn có thể bổ sung thêmC
. - Các thư mục chứa mã nguồn
Source_Dirs
sẽ sử dụngsrc/**
để truy vấn cả các thư mục con bên trong thư mụcsrc
. Như vậy chúng ta sẽ có thể sắp xếp các tệp code thành các nhóm dễ dàng hơn. - Tệp code khởi chạy đổi tên thành
main.adb
. - Các tham số sử dụng cho lệnh
gprbuild
bao gồm:-gnat2020
để hỗ trợ những tính năng mới nhất của ngôn ngữ.-gnata
để hỗ trợ tính năng kiểm thứ vớiassertion
và cho phép sử dụngcontract
.
name = "console_tictactoe"
description = "The Tic-Tac-Toe Gameboard in Console Window"
version = "0.1.0"
...
executables = ["main"]
Tệp khai báo project
của alire
cũng cần chỉnh sửa lại tên tệp thực thi executables
sau khi biên dịch xong là main
. Thông thường thì gprbuild
sẽ tạo ra tệp này cùng với các tệp hỗ trợ tiến trình biên dịch và đặt tất cả trong thư mục obj
. Ở đây alire
sẽ tự động chuyển tệp thực thi vào thư mục riêng có tên là bin
.
Source Modules
Như đã nói trước đó thì chúng ta sẽ thiết kế các procedure
xoay quanh các state
. Và ở đây, chúng ta có các nhóm state
là:
console-io
– dữ liệu trạng thái của cửa sổ dòng lệnh nơi nhận tương tác nhập liệu của người sử dụng.app-model
– dữ liệu trạng thái mô tả bảng Tic-Tac-Toe trong suốt quá trình tương tác với người dùng.
Như vậy thư mục src
của chúng ta sẽ có cấu trúc khởi đầu như thế này:
src
├── app-model
│ ├── app-model.adb
│ └── app-model.ads
├── console-io
│ ├── console_io.adb
│ └── console_io.ads
└── main.adb
Và bây giờ thì chúng ta sẽ bắt đầu viết code để tạo ra một gameboard
Tic-Tac-Toe trên nền console
.
[Procedural Programming + Ada] Bài 14 – Console Tic-Tac-Toe App (tiếp theo)
Nguồn: viblo.asia