[Declarative Programming + Elm] Bài 4 – Math & Type Variable

Bây giờ chúng ta sẽ bắt đầu nói về các điểm cần lưu ý về các thao tác xử lý phổ biến đối với các kiểu dữ liệu đã được giới thiệu trong bài viết trước. Tuy nhiên thì trước khi bắt đầu với các ví dụ chi tiết, mình vẫn muốn liệt kê lại

Bây giờ chúng ta sẽ bắt đầu nói về các điểm cần lưu ý về các thao tác xử lý phổ biến đối với các kiểu
dữ liệu đã được giới thiệu trong bài viết trước. Tuy nhiên thì trước khi bắt đầu với các ví dụ chi tiết,
mình vẫn muốn liệt kê lại danh sách tên các kiểu dữ liệu ở đây để chúng ta có thể tiện theo dõi
mạch logic và liên hệ giữa các kiểu (nếu có) –

  • Float, Int, number – các giá trị số học. Ví dụ: 10.01, 10, …
  • Bool – các giá trị nhận định logic TrueFalse
  • Char – các ký tự đơn. Ví dụ: 'A', 'z', …
  • String – các chuỗi văn bản. Ví dụ: "Elm Language"
  • Record – mô tả các bản ghi giống với C structJS Object
  • Tuple – mô tả các bản ghi ngắn gọn không có tên trường dữ liệu
  • List – lưu trữ các giá trị cùng kiểu theo dạng danh sách liệt kê

Ok.. chúng ta bắt đầu thôi. Để tiết kiệm thời gian thì chúng ta sẽ tương tác với Elm REPL giống như
bài viết trước. Tuy nhiên, bạn có thể tạo các tệp module để lưu lại code ví dụ nếu muốn.

cd Documents && cd learn-elm
elm repl

Các phép tính số học

Package:elm/core/Basics

Không có gì khác biệt nhiều so với các ngôn ngữ Imperative như C hay JavaScript mà chúng
ta đã biết. Các phép tính +, -, *, / căn bản.

1.0 + 2.0
-- 3 : Float

Tuy nhiên, lưu ý đầu tiên là Elm không hỗ trợ tự động chuyển kiểu dữ liệu từ Int sang Float.
Giá trị trả về bởi round được định kiểu Int, và 1 : Int thì không thể cộng trực tiếp với
2.0 : Float

(round 1.0) + 2.0
-- thông báo lỗi

Thế nhưng 1 : number2.0 : Float thì lại hợp lệ với phép tính + như vậy. Về lý do thì
chúng ta sẽ để dành cho hạng mục cuối bài. 😄

1 + 2.0
-- 3 : Float

Có phép chia lấy phần nguyên với ký hiệu // thì mình chưa gặp bao giờ.

9 // 2
-- 4 : Int

Phép lũy thừa sử dụng ký hiệu ^, khác với ** của JS.

2 ^ 10
-- 1024 : number

Ngoài ra thì các thao tác khác sẽ được xử lý bởi các sub-program. Ví dụ như phép chia lấy phần dư
9 % 2 trong JS

remainderBy 2 9
-- 1 : Int

Lấy giá trị nghịch đảo của một số trong Elm sẽ không sử dụng phép toán -. Lý do thì mình xin để
dành sang hẳn Sub-Series tiếp theo. Ở đây chúng ta cứ xem như quy ước xử lý đặc biệt và sử dụng
như vậy đi. 😄

negate -9
-- 9 : number

Giá trị tuyệt đối –

abs 10.01
-- 10.01 : Float

abs -10.01
-- 10.01 : Float

Căn bậc 2 –

sqrt 81
-- 9 : Float

Làm tròn giá trị tới biên gần –

round 10.01
-- 10 : Int

round 1.9
-- 2 : Int

Làm tròn lên và xuống –

ceiling 9.5
-- 10 : Int

floor 9.5
-- 9 : Int

Suy giảm về gốc 0 –

truncate 9.8
-- 9 : Int

truncate -9.8
-- -9 : Int

Kiểm tra NaN của một giá trị thu được từ một phép thực thi trả về kiểu Float

isNaN (0/0)       -- True
isNaN (sqrt -1)   -- True : Bool
isNaN 1           -- False : Bool

Phép chia cho 0/0 và lấy căn bậc hai của -1 không thể cho kết quả có ý nghĩa số học, do đó
nên chúng ta thu được giá trị NaN. Tuy nhiên trường hợp dưới dây thì kết quả là dương vô cùng
Infinite vẫn thuộc kiểu Float.

isNaN (1/0)
-- False : Bool

và để kiểm tra một giá trị trả về từ một thao tác định kiểu Float có phải là Infinite hay không –

isInfinite (0/0)       -- False
isInfinite (sqrt -1)   -- False
isInfinite (1/0)       -- True
isInfinite 1           -- False

NaNInfinite về căn bản là khác nhau: NaN không có ý nghĩa số học, còn Infinite thì là
một giá trị số học.

Các phép tính logic

Các ký hiệu &&|| được Elm sử dụng với ý nghĩa tương tự như CJS. Tuy nhiên phép
phủ định hay còn được gọi là lấy nghịch đảo một giá trị Bool được xử lý bằng chương trình not,
thay vì ký hiệu ! như CJS.

not True
-- False : Bool

not False
-- True : Bool

Các phép nhận định so sánh, hầu hết vẫn sử dụng các ký hiệu như chúng ta đã biết là ==, >,
<, >=, <=. Duy nhất có ký hiệu != trong CJS để kiểm tra nhận định hai giá trị là
khác nhau, được Elm thay thế bởi /=.

1 /= 0.9
-- True : Bool

1 /= 1.0
-- False : Bool

Type Variable

Các ngôn ngữ thuần Declarative hầu hết đều được xây dựng với một tinh thần chung – đó là
khả năng định kiểu rất mạnh mẽ và nghiêm ngặt strong-typing. Và ở đây chúng ta có Elm
là một trong số đó.

Cụ thể là thông báo lỗi như ví dụ phép tính + giữa một giá trị Int và một giá trị Float
chúng ta đã nhìn thấy ở phần đầu của bài viết. Mặc dù trình biên dịch compiler của Elm đã
có đủ thông tin về các giá trị nhận được trước khi thực hiện phép tính, tuy nhiên chỉ đơn giản là
Elm không hỗ trợ tự động chuyển đổi kiểu ngầm định trong trường hợp này. Và chúng ta sẽ
cần phải thực hiện việc chuyển kiểu dữ liệu trong code của mình –

(toFloat (round 1.0)) + 2.0
-- 3 : Float

Ồ thế nhưng tại sao phép tính 1 + 2.0 lại không có thông báo lỗi ?

Giá trị 1 trả về bởi round
được định kiểu là Int. Còn giá trị 1 mà chúng ta viết trực tiếp vào trong tệp code của chúng ta
thì lại chưa được định kiểu cố định, do đó nên Elm sẽ xem là một giá trị thuộc kiểu biến thiên number.

Khái niệm kiểu biến thiên Type Variable, có thể hiểu đơn giản là một kiểu dữ liệu bất kỳ mà trình
biên dịch compiler không tìm thông tin định kiểu rõ ràng trong code. Và sẽ cố gắng tìm một logic
xử lý thành công phù hợp nhất khi nhận được giá trị thực tế tại thời gian vận hành code runtime.

Chính xác thì một kiểu biến thiên a được hiểu là một kiểu Union bao gồm tất cả các kiểu dữ liệu
mà trình biên dịch thu thập được trong code định nghĩa của toàn bộ chương trình project. Tuy
nhiên, Elm cũng có tạo ra một vài Type Variable với khả năng hữu hạn hơn so với a. Đó là –

  • number – là một giá trị số học; Vì vậy nên có thể là Float hoặc Int.
  • comparable – là một giá trị có thể so sánh được bằng chương trình compare; Bao gồm Int, Float, Char, String, và List/Tupple của các kiểu đó.
  • appendable – là một giá trị có thể thực hiện các thao tác nối ghép nội dung; Vì vậy nên có thể là String hoặc List.
  • compappend – là một giá trị vừa thuộc comparable và vừa thuộc appendable.

Như vậy khi trình biên dịch đọc phép tính 1 + 2.0 thì giá trị 2.0 đã có đủ thông tin định kiểu
rõ ràng là Float do có dấu phẩy thập phân .; Còn giá trị 1 thì chưa có thông tin định kiểu
cụ thể nên sẽ là number. Logic thành công phù hợp nhất là Float + Float và chúng ta có
logic được biên dịch là 1.0 + 2.0. Phép tính được thực hiện và không có thông báo lỗi.

comparable

Nhân tiện sau khi giới thiệu xong khái niệm kiểu biến thiên Type Variable thì chúng ta đang có
vài kiểu được định nghĩa sẵn như đã được liệt kê ở trên. Cái number thì chúng ta đã vừa sử dụng
để làm ví dụ minh họa ở trên rồi, và trong số mấy kiểu còn lại thì ở đây chúng ta đã có đủ kiến
thức để nói về comparable.

Một giá trị thuộc kiểu comparable sẽ có thể được sử dụng trong một thao tác so sánh bằng
chương trình compare.

Ở chỗ này chúng ta cần lưu ý một chút để tránh nhầm lẫn. Các phép toán logic >, <, ==,
/=, v.v… mà trả về các giá trị Bool thì được sử dụng để kiểm tra một nhận định so sánh. Hay
nói cách khác là để kiểm tra một sự đánh giá. Và thao tác kiểm tra như vậy sẽ mang ý nghĩa
có phần hơi khác một chút với thao tác so sánh bằng
compare mà chúng
ta vừa nói ở trên.

Một phép kiểm tra a == b sẽ đưa ra kết quả trả lời cho câu hỏi: “a có giá trị bằng b. Đúng
hay Sai? Nếu đúng thì chọn True, còn nếu sai thì chọn False. 30 giây suy nghĩ bắt đầu !”

1 == 0.9
-- False : Bool

Còn một phép so sánh compare a b, ở mặt khác, sẽ đưa ra kết quả trả lời cho câu hỏi: “a so
với b thì thế nào? Bằng à EQ? Hay nhỏ hơn LT? Hay lớn hơn GT? Trả lời ngay và luôn !”

compare 1 0.9
-- GT : Order

Kết quả của một phép so sánh, sau đó, hiển nhiên cũng sẽ có thể được sử dụng để điều hướng
logic hoạt động của code mà chúng ta xây dựng. Và Elm cũng có một vài chương trình cơ bản,
rất hữu ích, cần sử dụng tới các giá trị Order này.

-- max : comparable -> comparable -> comparable
max 1 0.9

-- min : comparable -> comparable -> comparable
min "abc" "xyz"

Về việc hai chuỗi "abc""xyz" được compare với logic như thế nào thì chúng ta sẽ để dành
cho bài viết tiếp theo. 😄

(chưa đăng tải) [Declarative Programming + Elm] Bài 5 – String & List

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ