[Declarative Programming + Elm] Bài 2 – Basic Syntax

Sau khi đã copy/paste và chạy thử thành công chương trình Hello World đơn giản thì chúng ta đã có thể bắt đầu xem xét từng yếu tố mới mẻ trong cú pháp của một ngôn ngữ lập trình thuần Declarative. Câu chuyện lúc này quay trở lại với phần định nghĩa căn bản song

Sau khi đã copy/paste và chạy thử thành công chương trình Hello World đơn giản thì chúng ta đã có thể bắt đầu xem xét từng yếu tố mới mẻ trong cú pháp của một ngôn ngữ lập trình thuần Declarative. Câu chuyện lúc này quay trở lại với phần định nghĩa căn bản song song của hai mô hình lập trình Imperative ProgrammingDeclarative Programming.

Ngôn ngữ thuần Declarative

Như đã giới thiệu trước đó trong bài viết [JavaScript] Bài 23 – Imperative & Declarative của Series Tự Học Lập Trình Web, thì từ Imperative chỉ đơn giản là để mô tả khía cạnh tạo nên logic hoạt động của code bằng các câu lệnh tuần tự. Trong hầu hết các ngôn ngữ lập trình thì người ta còn sử dụng thêm các cú pháp Declarative cho phép người viết code đặt tên cho các đoạn code nhằm mục đích sắp xếp kiến trúc của chương trình, có thể là các chương trình con sub-program, hay các hàm function, hay class, v.v….

Và thường thì các ngôn ngữ lập trình phổ biến được gọi là Imperative thì có nghĩa là sẽ có yếu tố đầu tiên đóng vai trò chủ đạo, chứ không hẳn là thuần Imperative 100%. Còn nếu một ngôn ngữ nào đó được gọi là Declarative thì ngoài khả năng trộn lẫn các yếu tố Imperative ví dụ như SQL, chúng ta còn có thể sẽ bắt gặp các ngôn ngữ thuần Declarative 99.99%.

À.. chỗ này thì chúng ta có thể hiểu là chương trình được viết bởi một ngôn ngữ thuần Declarative sẽ không có các câu lệnh logic tuần tự. Các chương trình con sub-program và cả những yếu tố khác nữa trong môi trường thuần Declarative, sẽ được tạo ra hoàn toàn bằng các cú pháp khai báo và biểu đạt logic tương quan với nhau chứ không được xây dựng bởi các câu lệnh logic tuần tự. Xuất phát từ chương trình chính main là điểm khởi chạy một chương trình bất kỳ, chúng ta có định nghĩa ngắn gọn thế này –

output = main (input)

Đó có nghĩa là khi sử dụng một chương trình program bất kỳ thì chúng ta luôn dự kiến một kết quả output sẽ có thể thu được từ việc gọi chương trình chính main với một tham số đầu vào input. Cái dạng thức này hình như là được ảnh hưởng từ một lĩnh vực nào đó khác thì phải. 😄

y = f(x)

Chắc chắn là như vậy rồi. 😄 Thế rồi logic xử lý bên trong của chương trình main sẽ được biểu thị như thế nào nếu như chúng ta không được sử dụng các câu lệnh logic tuần tự? Hãy xem cùng xem lại code chương trình Hello Elm ! ở bài viết trước một chút.

moduleMainexposing(main)import Html exposing(Html,text)main:Htmlmessagemain=text"Hello Elm !"

Ở đây chúng ta có code logic của chương trình chính main chỉ có một dòng duy nhất là –

-- ...main=text"Hello Elm !"

Và dòng code này có thể được đọc là chương trình chính main không yêu cầu tham số đầu vào và được định nghĩa là = kết quả của việc chạy chương trình con text với tham số truyền vào là chuỗi Hello Elm !. Như vậy là điểm mới mẻ đầu tiên mà chúng ta nhận thấy trong cú pháp của Elm đó là khi gọi một sub-program, chúng ta sẽ không cần phải viết các dấu ngoặc đơn () như cú pháp của C hay JavaScript.

Bây giờ chúng ta sẽ chỉnh sửa lại chương trình này một chút và thử xem cú pháp khai báo một sub-program có yêu cầu tham số đầu vào trông như thế nào –

moduleMainexposing(main)import Html exposing(Html,text)main:Htmlmessagemain=greet"Elm"greet:String->Htmlmessagegreetname=text("Hello "++name++" again !")

Sau khi sửa lại code, tại cửa sổ dòng lệnh, bạn chạy câu lệnh sau –

elm reactor

Lúc này trình biên dịch elm sẽ tạo một HTTP server tự động cập nhật kết quả code và chúng ta sẽ không cần phải gõ lại lệnh elm make nữa. Tệp index.html và thư mục hỗ trợ elm-stuff đều có thể được xóa đi và chỉ khi nào chúng ta đã học đủ kiến thức về cú pháp ngôn ngữ và các công cụ để xây dựng một trang web đơn thì mới cần thiết phải biên dịch thành tệp thực thi như vậy. Để xem kết quả vận hành của code, bạn mở cửa sổ trình duyệt web và truy cập vào địa chỉ dưới đây –

http://localhost:8000/

Ở giao diện quản lý tệp hiện ra trong cửa sổ trình duyệt web, bạn mở thư mục src và nhấn vào tên tệp Main.elm để xem kết quả vận hành của code mới chỉnh sửa lại.

http://localhost:8000/src/Main.elm

Như vậy là để khai báo hay định nghĩa một sub-program có yêu cầu tham số đầu vào thì chúng ta chỉ cần viết tên của tham số đó ngay sau tên của sub-program

-- ...greetname=text("Hello "++name++" again !")

Và ở đây thì chúng ta có một cặp ngoặc đơn () để ưu tiên xử lý cho biểu thức nối các chuỗi ký tự thành một câu chào trước khi truyền vào chương trình con text. Cũng không có gì khác biệt nhiều lắm so với cách sử dụng ngoặc đơn () để nâng mức ưu tiên xử lý cho một đoạn code trong C hay JavaScript mà chúng ta đã biết.

Như vậy thì nhìn chung là chúng ta sẽ có một chương trình được viết trong môi trường thuần Declarative sẽ là các lời gọi xếp chồng của các chương trình con để xử lý từ phần một của logic cần biểu thị cho đến khi thu được kết quả output cuối cùng. Hiển nhiên là bên cạnh đó thì chúng ta cũng sẽ có những cú pháp hỗ trợ khác nữa để diễn đạt logic của chương trình ngắn gọn, xúc tích, và liền lạc hơn, để giảm thiểu số lượng các sub-program cần được tạo ra. 😄

Định kiểu dữ liệu

Giống với C, trình biên dịch của Elm sẽ giúp chúng ta sàng lọc những lỗi lập trình tiềm ẩn bằng cách duyệt qua các yếu tố định kiểu type-hinting trong code mà chúng ta viết, để đảm bảo rằng chương trình sau khi được biên dịch xong sẽ không có lỗi phát sinh trong quá trình vận hành runtime error.

Và ở đây Elm cũng có một cơ chế tự động ngầm định kiểu dữ liệu của các biến hay các tham số nếu như đã có đủ thông tin nhờ các phép thực thi operator hay các sub-program đang sử dụng các biến này. Mặc dù vậy thì chúng ta vẫn nên khởi đầu ngay với việc học cách viết type-hinting đầy đủ như code ví dụ mà mình đã copy/paste để giới thiệu trong các ví dụ trước đó.

Cụ thể là chúng ta có chương trình con greet được type-hint là sẽ nhận vào một tham số kiểu String và trả về kết quả là một chương trình con Html được gắn kèm tham số message.

-- ...greet:String->Htmlmessage

Còn chương trình chính main như đã nói trước đó là sẽ không yêu cầu tham số đầu vào và cũng trả về kết quả thuộc kiểu Html message.

Sử dụng Module

Yếu tố còn lại mà chúng ta chưa nói đến trong chương trình mở đầu đó là các tên định danh như kiểu chương trình con Html message, hay chương trình con text được cung cấp từ dòng import ở phía trên.

-- ...import Html exposing(Html,text)

Dòng này thì có thể hiểu đơn giản là chúng ta đang import một module có sẵn với tên là Html phần exposing (Html, text) là để khi viết code sử dụng các tên định danh này ở phía bên dưới thì chúng ta sẽ không phải viết lại nhiều lần tên của module đứng ở phía trước và tham chiếu bởi dấu . như thế này –

-- ...greet:String->Html.Htmlmessagegreetname=Html.text("Hello "++name++" again !")

Cuối cùng là tham số message trong dòng type-hint có thể được đặt tên định danh tùy ý giống như tham số name đối với chương trình con greet. Và trong hầu hết các trường hợp khi xây dựng các ứng dụng đơn giản, chúng ta sẽ không mấy khi gặp phải vấn đề trùng lặp tên định danh từ các module khác nhau; Do đó, chúng ta có thể viết tắt đoạn exposing thành ký hiệu biểu trưng .. thay cho danh sách các tên dịnh danh. Như vậy, tất cả các thành phần trong module được import, chắc chắn sẽ có thể được sử dụng bằng cách viết tên trực tiếp mà không tham chiếu bằng tên module đứng ở phía trước.

Đó là thao tác import một module để sử dụng. Bây giờ chúng ta sẽ tách chương trình con greet ra một module riêng. Trong thư mục src, chúng ta cần tạo thêm một tệp mới là Greet.elm và di chuyển code định nghĩa chương trình con greet vào như sau –

moduleGreetexposing(greet)import Html exposing(..)greet:String->Htmlmessagegreetname=text("Hello "++name++" Module !")

Để khai báo một module thì chúng ta cần viết ngay ở dòng đầu tiên của tệp đó và exposing để mở những thành phần mà chúng ta muốn code ở các module khác có thể import để sử dụng. Tuy nhiên khác với thao tác exposing khi import, khi khai báo các module, thường thì chúng ta nên liệt kê chính xác chỉ những thành phần muốn để mở cho code bên ngoài sử dụng, chứ không nên sử dụng cú pháp tự động exposing toàn bộ.

Ở tệp Main.elm, chúng ta thực hiện thao tác import Greet tương tự như đối với module Html và mặc định exposing tất cả các thành phần mà code định nghĩa của các module đó đã exposing ra bên ngoài.

moduleMainexposing(main)import Html exposing(..)import Greet exposing(..)main:Htmlmessagemain=greet"Elm"

http://localhost:8000/src/Main.elm

Như vậy là chúng ta đã nắm bắt được cú pháp căn bản của một ngôn ngữ thuần Declarative để biểu thị các sub-program đơn giản. Tiếp theo, chúng ta sẽ tìm hiểu về các kiểu dữ liệu căn bản và các cú pháp hỗ trợ, giúp cho chúng ta có khả năng biểu thị logic hoạt động phức tạp hơn khi định nghĩa các sub-program.

(Chưa đăng tải) [Declarative Programming + Elm] Bài 3 – …

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 đầ