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

[Functional Programming + Elm] Bài 1 - Functional Aspects

0 0 17

Người đăng: Semi Dev

Theo Viblo Asia

Song song với Procedural Programming, và ở cùng cấp độ quan sát về việc kiến trúc phần mềm từ các sub-program đó là mô hình Lập Trình Hàm Functional Programming, cũng đã được đề cập trước đó trong một bài viết của Sub-Series JavaScript. Ở thời điểm đó thì chúng ta đã điểm qua và so sánh song song một số nét đặc trưng của ProceduralFunctional.

Tuy nhiên trong khuôn khổ của một bài giới thiệu ngắn thì vẫn còn rất nhiều những điểm chi tiết mà mình không thể mang vào để giới thiệu về các mô hình lập trình này. Và cụ thể là sau khi đi qua Sub-Series Ada thì điều đó lại càng rõ ràng, những công cụ lập trình và các khái niệm liên quan, được cung cấp bởi một ngôn ngữ được thiết kế trọng tâm hướng đến Procedural có nhiều phần không thể liệt kê được trong một bài viết.

Và bây giờ đã là thời điểm phù hợp để chúng ta tìm hiểu chi tiết về các công cụ và các khái niệm liên quan mà một ngôn ngữ được thiết kế trọng tâm Functional cung cấp. Thực tế thì để tìm hiểu về Functional Programming một cách nghiêm túc và sử dụng những lợi điểm của Functional thì môi trường thuận lợi nhất hiện tại đang là ngôn ngữ Haskell. Tuy nhiên để duy trì lượng cú pháp phải ghi nhớ tạm ở mức độ phù hợp thì mình đã chọn phương thức học tham chiếu từ Haskell và triển khai trong Elm với hết khả năng mà Elm đang có.

Mặc dù cũng là một ngôn ngữ thuần Functional nhưng so với Haskell thì Elm hỗ trợ ít cú pháp biểu thị code hơn và chỉ kèm theo vừa đủ các công cụ mang tính kiến trúc căn bản. Một số khái niệm về các công cụ tạo dạng thức triển khai code Functional được Haskell hỗ trợ sẵn như Type Class, Functor, Monad, v.v... khi muốn sử dụng trong Elm thì chúng ta sẽ phải tự định nghĩa mô phỏng lại. Tuy nhiên điều đó cũng sẽ đem lại điều kiện để chúng ta hiểu rõ hơn về các công cụ này và nắm bắt tốt hơn tư duy lập trình hàm.

Functional Aspects

Trong Sub-Series trước của Elm, chúng ta đã nói về Declarative Programming - một trong hai mô thức căn bản để viết một đoạn code mô tả logic cần máy tính thực hiện. Tuy nhiên Declarative cũng giống như Imperative, chỉ nói về việc biểu thị logic ở cấp độ chi tiết chứ không phải là ở cấp độ kiến trúc chương trình. Và sau đó, khi bắt đầu quan tâm tới việc thiết kế và tổ chức các sub-program thì chúng ta mới có ProceduralFunctional.

Điều đó có nghĩa là một ngôn ngữ Procedural cũng có thể được thiết kế với cú pháp sử dụng ở dạng Declarative, ví dụ như SQL; Và một ngôn ngữ Functional cũng có thể được thiết kế với cú pháp sử dụng ở dạng Imperative, ví dụ như F-sharp. Tuy nhiên sự thực thì đúng là các ngôn ngữ thuần Functional đều sử dụng cú pháp Declarative, và tuyệt đại đa số các ngôn ngữ Procedural đều sử dụng cú pháp Imperative. 😄

Trong Sub-Series này thì chúng ta sẽ chỉ đề cập tới khía cạnh Functional được biểu thị trong Elm để tìm hiểu và có khả năng triển khai trong cả những ngôn ngữ Imperative như JavaScript nếu muốn.

first-class function & function composition
higher-order function & currying function
type variable & type class
functor & applicative
monoid & co-monad

Trên đây là danh sách liệt kê một số nét đặc trưng và khái niệm liên quan tới Functional Programming mà chúng ta sẽ tìm hiểu trong Sub-Series này với sự tham chiếu từ Haskell. Và trong bài viết mở đầu này thì chúng ta sẽ nói về các khái niệm First-Class FunctionFunction Composition.

First-Class Function

Đây là điểm đặc trưng căn bản nhất và quan trọng nhất để bất kỳ ngôn ngữ nào có thể được xem là có hỗ trợ Functional Programming. Khái niệm First-Class Function là cách nói ngắn gọn của câu Function is First-Class Citizen - có thể hiểu nôm na là các Hàm Function được xếp vào lớp các thành tố quan trọng nhất của phần mềm, tương đương với Kiểu Dữ Liệu Type. Và biểu thị cần được hỗ trợ đó là một Hàm có thể được xem là một giá trị Value, có thể được gán vào các biến, có thể được sử dụng làm các toán hạng của một biểu thức giữa các Hàm, có thể được truyền vào lời gọi Hàm khác, và có thể là kết quả trả về của một lời gọi Hàm nào đó.

Có thể gán một Hàm vào một biến để lưu trữ và sử dụng sau đó.

Chính vì lý do này nên mặc dù bạn có thể không chạm tới các ngôn ngữ thuần Functional nhưng khi dạo quanh một số ngôn ngữ lập trình phổ thông để tham khảo tính năng và cú pháp, thì khả năng rất lớn là bạn sẽ gặp nhiều trường hợp định nghĩa hàm trong một số ngôn ngữ có hỗ trợ viết ở dạng biểu thức với phép gán = vào một tên định danh nào đó. Kiểu cú pháp này chính là thứ xuất phát từ Functional Programming.

module Main exposing (main)
import Html exposing (Html, text) main : Html message
main = text (greet "Elm") greet : String -> String
greet name = "Hello " ++ name ++ " again !"

Và trong JavaScript như chúng ta đã biết từ Series lập trình web đầu tiên:

// -- greet : String -> String
const greet = (name) => "Hello" + name + "again !"

Hm... vị trí của phép gán = dường như có phần hơi khác nhau. Trong code ví dụ của Elm thì chúng ta đang có dạng mô tả hàm toán học f(x) = ... x ..., và trong đó thì vị trí của f chính là greet và vị trí của xname; Còn trong code ví dụ của JS thì tính từ vị trí (name) => ... có ý nghĩa tương đương với định nghĩa trong Elm và tạo ra một hàm f vô danh để gán vào hằng greet.

Tuy nhiên chúng ta cũng có thể sửa lại code main của Elm để biểu thị rõ ràng hơn rằng - Hàm Function cũng là một Giá Trị Value như các kiểu dữ liệu khác. Hãy thử gán hàm greet vào một biến trong hàm main, sau đó gọi hàm thông qua tên biến này.

-- module ... main : Html message
main = let make = greet in text (make "Elm") -- greet : ...

Function Composition

Khái niệm Kết Hợp Hàm Function Composition xuất hiện đồng thời với khái niệm First-Class Function đầu tiên, bởi mục đích của việc nhìn nhận một Hàm Function là một Giá Trị Value và yêu cầu thiết kế ngôn ngữ hỗ trợ việc lưu trữ Hàm vào biến là để chúng ta có thể thực hiện các phép toán trên các hàm và sau đó thu được một Hàm tổng bộ all-in-one và lưu vào một biến. Sau đó áp dụng hàm này trên dữ liệu đầu vào input và thu về kết quả output.

Ý tưởng này cũng được vay mượn từ Toán Học khi mà chúng ta biểu thức h(x) = f(g(x)) và khi một giá trị x được đặt vào h(x) thì đầu tiên chúng ta sẽ tính toán giá trị của biểu thức g(x) rồi sau đó tiếp tục đặt giá trị này vào vị trí tham số của hàm f để tính tiếp. Tuy nhiên, chúng ta cũng có thể viết h = f . g để biểu thị rằng hàm h là kết quả thu được khi kết hợp hàm f và hàm g để làm phẳng biểu thức h(x) trước khi đặt x vào và thực hiện tính toán trong một lượt.

main : Html message
main = let make = text << greet in make "Elm"

Ở đây chúng ta có code Hello, Elm ! được viết lại với main được định nghĩa là kết quả thu được sau khi gọi Hàm make với chuỗi "Elm", và hàm make lúc này được định nghĩa là hàm kết hợp được tạo ra từ hàm text và hàm greet. Và dạng thức viết code này sẽ được sử dụng rất nhiều trong các Hàm chủ đạo điều khiển logic hoạt động chính của chương trình, tương đương với vai trò của các Thủ Tục trong môi trường Procedural; Bởi như chúng ta đã biết thì trong môi trường Procedural, các function chỉ đóng vai trò sub-program hỗ trợ cho các procedure chủ đạo điều khiển logic hoạt động chính ngay dưới cấp của main.

Về việc phân chia vai trò của các Hàm chủ đạo và các Hàm tiện ích hỗ trợ các thao tác tính toán thì trong môi trường Functional không có quy ước nào. Tất cả hoàn toàn là lựa chọn của người viết code khi thiết kế các hàm và phải thực hiện ghi chú hay đưa ra quy ước đặt tên convention để tự sắp xếp.

(chưa đăng tải) [Functional Programming + Elm] Bài 2 - Higher-Order Function & Currying Function

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 51

- 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 31

- 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 27

- 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 47

- 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 266

- 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 35