1. Lập trình hàm

Lập trình hàm, còn gọi là lập trình chức năng (functional programming) là một phương pháp lập trình khá phổ biến và quan trọng trong khoa học máy tính. Tuy nhiên ở Việt Nam nói riêng và nhiều nước khác nói chung, sinh viên các ngành khoa học máy tính, hay công nghệ thông tin ít khi được dạy lập trình hàm ngay từ đầu. Người học thường sẽ được dạy phương pháp lập trình theo kiểu mệnh lệnh (imperative programming), điển hình là hai kiểu lập trình là lập trình thủ tục (procedural programming) và lập trình hướng đối tượng (object-oriented programming). Nhiều ngôn ngữ lập trình mà người học quen thuộc như C, C++, Java, Python… ban đầu được thiết kế theo phương pháp lập trình mệnh lệnh. Sau này, các phiên bản cải tiến hơn về sau đã thêm các tính năng lập trình hàm vào ngôn ngữ.

Bài viết ngắn này giới thiệu vắn tắt, theo cách hoàn toàn không hàn lâm, với mục đích để đa số người đọc, dù chưa bao giờ học hoặc nghe nói tới lập trình hàm đều có thể hiểu được. Điều kiện tiên quyết chỉ là người đọc biết lập trình cơ bản.

Vấn đề bản chất và cốt lõi nhất trong lập trình hàm là quan niệm coi rằng các cấu trúc và tính toán của một chương trình là việc áp dụng các hàm toán học và tránh thay đổi các trạng thái của dữ liệu.

Trong môn toán, chúng ta thường viết \( y = f(x) \), tức \( y \) là một hàm của \( x \). Nếu \( x \) là dữ liệu, \( f \) là tính toán thì \( y \) là kết quả của tính toán đó. Việc tính \( f(x) \) không làm thay đổi \( x \), và với mỗi \( x \) thì chỉ có một \( y \). Khi gọi hàm \( f \) nhiều lần trên cùng một dữ liệu \( x \) thì ta sẽ nhận được các kết quả giống nhau. Điều này giúp tránh được các hiệu ứng phụ (side-effects) vốn thường gặp trong các ngôn ngữ lập trình không chức năng.

Trong những năm gần đây, ngày càng nhiều ngôn ngữ lập trình chức năng được sử dụng, không những trong giới hàn lâm và còn trong cả công nghiệp. Một số ngôn ngữ lập trình hỗ trợ đồng thời nhiều phong cách lập trình, kết hợp cả lập trình mệnh lệnh, lập trình hướng đối tượng, lập trình chức năng. Điển hình có thể kể đến là các ngôn ngữ Scala, Python và JavaScript.

2. Ngôn ngữ lập trình Scala

Scala là ngôn ngữ lập trình chạy trên nền Java, hỗ trợ vừa hướng đối tượng, vừa lập trình hàm, có cú pháp gọn hơn Java nhiều (có thể so sánh độ gọn với Python). Scala có nhiều ưu điểm, chưa kể một số nền tảng tính toán phân tán, xử lí dữ liệu lớn phổ dụng hiện nay như Apache Spark được viết bằng Scala.

Bạn có thể tham khảo website của Scala để tự học thêm về ngôn ngữ này. Ngay cả khi bạn đã là một lập trình viên lâu năm, nhiều kinh nghiệm với các ngôn ngữ lập trình hướng đối tượng, thì việc học thêm một phong cách lập trình khác, một ngôn ngữ lập trình khác cũng là điều tốt. Nó giúp bạn ngày càng nâng cao tư duy lập trình và ngày càng lập trình hiệu quả hơn.

3. Một số ví dụ đơn giản

Trong mục này, ta giới thiệu một số ví dụ nhỏ minh hoạ tư duy lập trình hàm bằng ngôn ngữ lập trình Scala.

3.1. Tính tổng một mảng số nguyên

Các cấu trúc dữ liệu thường dùng trong Scala đều có sẵn nhiều hàm thông dụng, cụ thể ở đây là hàm tính tổng. Ví dụ, đoạn mã dưới đây khai báo một mảng các số nguyên, tính tổng của mảng đó bằng hàm sum và in kết quả ra màn hình:

Ta có thể thấy, cách từ duy của lập trình hàm trong bài toán này là coi \( x \) là một mảng, \( f \) là hàm tính tổng, và \( y \) là kết quả, \( y = f(x) \). Trong Java, ta cần viết một vòng lặp, khởi tạo một biến s và cộng dồn từng số trong mảng vào biến đó.

3.2. Tính tổng bình phương các phần tử trong mảng số nguyên

Chúng ta tiếp tục ví dụ trên, ta muốn tính tổng

\( s = 1^2 + 3^2 + 5^2 + 7^2 + 9^2 \)

Về mặt toán học, ở đây ta sẽ cần sử dụng hai hàm, một hàm tính bình phương của một số và một hàm tính tổng của nhiều số. Trước hết, ta sử dụng hàm map (ánh xạ) tác động lên mảng số để biến mỗi phần tử của mảng đó thành một số chính phương, sau đó mới dùng hàm sum để tính tổng:

Trong toán, ta gọi đây là phép tổ hợp hàm, hay dùng hàm hợp:\( y = g (f(.)) \), trong đó \( f \) và \( g \) là các hàm. Ký hiệu mũi tên \( => \) chính là phép biến đổi hàm, chuyển mỗi số vào \( x \) thành số ra tương ứng là \( x^2 \).

3.3. Lọc các phần tử thoả mãn điều kiện nào đó

Tiếp tục ví dụ 1, nếu ta muốn lọc ra các phần từ không bé hơn 5 của mảng xs thì ta đơn giản chỉ cần dùng hàm filter như sau:

Lệnh thứ nhất tạo ra một mảng ys từ xs chỉ chứa các số không bé hơn 5. Lệnh thứ hai in các phần tử của ys ra màn hình. Biến cục bộ hình thức x trong lệnh thứ nhất thậm chí có thể bỏ đi cho gọn hơn, thay bằng kí hiệu gạch dưới:

Ở đây, kí hiệu gạch dưới đại diện cho mỗi phần tử của mảng xs. Để ý rằng tham số của hàm filter là một hàm logic nhận các giá trị true hoặc false biểu diễn điều kiện lọc; chỉ những giá trị nào của xs thỏa mãn điều kiện lọc thì mới được giữ lại. Lưu ý rằng, các hàm ta dùng ở trên như sum, map, filter đều không làm thay đổi gì dữ liệu xs ban đầu.

4. Tạm kết

Bài viết ngắn này giới thiệu sơ sơ về lập trình hàm và ngôn ngữ lập trình Scala. Phương pháp lập trình hàm còn có nhiều khái niệm quan trọng và chuyên sâu khác như hàm bậc cao, hàm bộ phận, đệ quy, các hệ định kiểu… như trên ảnh đầu của bài viết. Nếu có dịp, trong một số bài viết sau, chúng ta sẽ dần tìm hiểu thêm các khái niệm này và ví dụ minh họa.

Lê Hồng Phương
Theo ereka

Tin liên quan: