- vừa được xem lúc

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

0 0 24

Người đăng: Semi Art

Theo Viblo Asia

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 và so sánh

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 mà 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

Bình luận

Bài viết tương tự

- vừa được xem lúc

Closure trong Javascript - Phần 2: Định nghĩa và cách dùng

Các bạn có thể đọc qua phần 1 ở đây. Để mọi người không quên, mình xin tóm tắt gọn lại khái niệm lexical environment:.

0 0 67

- vừa được xem lúc

Var vs let vs const? Các cách khai báo biến và hằng trong Javascript

Dạo này mình tập tành học Javascript, thấy có 2 cách khai báo biến khác nhau nên đã tìm tòi sự khác biệt. Nay xin đăng lên đây để mọi người đọc xong hy vọng phân biệt được giữa let và var, và sau đó là khai báo hằng bằng const.

0 0 47

- vừa được xem lúc

VueJS: Tính năng Mixins

Chào mọi người, hôm nay mình sẽ viết về Mixins và 1 số vấn đề trong sử dụng Mixins hay ho mà mình gặp trong dự án thực. Trích dẫn từ trang chủ của VueJS:.

0 0 41

- vừa được xem lúc

Asset Pipeline là cái chi chi?

Asset Pipeline. Asset pipeline là cái chi chi. . Giải thích:.

0 0 75

- vừa được xem lúc

Tạo data table web app lấy dữ liệu từ Google Sheets sử dụng Apps Script

Google Sheets là công cụ tuyệt vời để lưu trữ bảng tính trực tuyến, bạn có thể truy cập bảng tính bất kỳ lúc nào ở bất kỳ đâu và luôn sẵn sàng để chia sẻ với người khác. Bài này gồm 2 phần.

0 0 280

- vừa được xem lúc

Học Deep Learning trên Coursera miễn phí

Bạn muốn bắt đầu với Deep Learning nhưng không biết bắt đầu từ đâu? Bạn muốn có một công việc ở mức fresher về Deep Learning? Bạn muốn khoe bạn bè về kiến thức Deep Learning của mình. Bắt đầu từ đâu.

0 0 50