Trở thành Functional Programmer - Phần 6
Đây là bài dịch từ bài gốc ở link sau : https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-6-db502830403#.ixhzsy2zb Những bước đầu tiên của việc hiểu rõ các concepts trong lập trình hàm (Functional Programming - FP) là những bước quan trọng nhất, và đôi khi là những ...
Đây là bài dịch từ bài gốc ở link sau : https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-6-db502830403#.ixhzsy2zb
Những bước đầu tiên của việc hiểu rõ các concepts trong lập trình hàm (Functional Programming - FP) là những bước quan trọng nhất, và đôi khi là những bước khó khăn nhất. Nhưng với cách tiếp cận đúng đắn, mọi thứ sẽ trở nên dễ hiểu hơn rất nhiều. Và đây là series được tạo ra nhằm mục đích giúp các bạn dễ thở hơn trong quá trình tiếp cận với FP.
Link của các phần trước: Phần 1, Phần 2, Phần 3, Phần 4, Phần 5
Bước tiếp theo
Thông qua 5 phần trước, tôi đã giới thiệu đến các bạn tất cả các concepts tuyệt vời mà FP mang lại, nhưng đồng thời cũng dấy lên trong các bạn câu hỏi : "Giờ thì sao? Liệu những kiến thức đó có thể có ích gì cho tôi trong công việc hàng ngày chứ?"
Câu trả lời sẽ là tùy theo từng người. Nếu bạn có thể/đang làm việc với các ngôn ngữ Pure Functional Language như là Elm hay Haskell, thì bạn có thể tận dụng toàn bộ những kiến thức đã đề cập đến, đồng thời các ngôn ngữ đó sẽ hỗ trợ bạn trong việc vận dụng chúng một cách thuận tiện nhất.
Còn nếu bạn vẫn đang tiếp tục sử dụng các ngôn ngữ Imperative như Javascript - giống như hầu hết các lập trình viên hiện nay, thì bạn vẫn có thể vận dụng những concepts đã học được, nhưng sẽ cần một vài tùy chỉnh và nguyên tắc cần tuân thủ.
Functional Javascript - Code JS theo hướng Functional
Javascript có thể thực hiện rất nhiều concepts của FP. Mặc dù nó không thuần khiết (pure) cho lắm, nhưng JS vẫn có lựa chọn để sử dụng khả năng immutability (tính bất biến) hoặc nếu sử dụng các thư viện đã có, thì việc hỗ trợ FP concepts còn mạnh mẽ hơn.
Mặc dù áp dụng FP vào JS không hoàn toàn lý tưởng, nhưng nếu bạn có thể tận dụng một vài lợi ích từ FP thì tại sao không thử nhỉ?
Immutability - Tính bất biến
Điều đầu tiên mà ta có thể xem xét áp dụng là tính bất biến. Trong phiên bản ES2015 - hay còn gọi là ES6, có một từ khóa mới đã được giới thiệu có tên là const. Và đúng như tên gọi của từ khóa này, nó được dùng để khai báo một biến mà giá trị không thể gán lại được :
const a = 1; a = 2; // sẽ có exception có tên là TypeError trong Chrome, Firefox hoặc Node // nhưng không có nếu dùng Safari (bản 10/2016)
Ở đây biến a được khai báo là một hằng số (const) nên nó sẽ không thể được set lại giá trị nữa. Vì thế mà đoạn code a = 2 sẽ sinh ra Exception (ngoại trừ Safari).
Tuy nhiên, có một vấn đề với const, đó là nó vẫn chưa hoàn toàn implement tính bất biến một cách đầy đủ. Đoạn code dưới đây sẽ thể hiện hạn chế này:
const a = { x: 1, y: 2 }; a.x = 2; // KHÔNG CÓ EXCEPTION! a = {}; // có exception TypeError
Bạn sẽ thấy rằng khi set a.x = 2 thì sẽ không gây ra lỗi. Thứ duy nhất mà từ khóa const áp dụng để kiểm tra tính bất biến chỉ là biến a. Còn tất cả những thành phần mà a có thể liên kết đến thì vẫn có thể thay đổi được (Ở đây sẽ hiểu là keyword const chỉ check a có là object vẫn tạo ra từ đầu hay không, mà không check được các thuộc tính của a bị thay đổi).
Tôi thấy khá là thất vọng khi nhận ra điều này, vì nếu được implement một cách hoàn hảo, JS đã có thể trở nên tốt hơn rất nhiều.
Vậy liệu có cách nào để chúng ta có thể áp dụng tính bất biến vào JS một cách toàn diện nhất không?
Câu trả lời là Có thể, nhưng chúng ta phải sử dụng một thư viện có tên là Immutable. Thư viện này sẽ hỗ trợ tính bất biến tốt hơn so với const nhưng lại khiến code của chúng ta giống Java hơn là Javascript.
Currying và Composition
Ở các series trước đó, chúng ta đã học được cách viết hàm hỗ trợ khả năng Currying. Dưới đây là một ví dụ phức tạp hơn:
const f = a => b => c => d => a + b + c + d
Để ý rằng phiền toái đầu tiên là chúng ta phải chỉ rõ phần currying (a => b => c => d)
Và nếu phải gọi hàm f, thì mọi thứ sẽ còn phức tạp hơn
console.log(f(1)(2)(3)(4)); // prints 10
Quá nhiều dấu ngoặc đơn như trên là đủ để khiến lập trình Lisp phải khóc ròng rồi (Lisp dùng nhiều dấu ngoặc đơn, nên nếu lập trình viên Lisp còn phải khóc trước số lượng dấu ngoặc đơn như này thì đủ thấy sự kinh khủng của dòng code trên là như nào