# Monad trong lập trình hàm: từ Monoid đến Functor
## 1. Mở đầu
Trong lập trình hàm, bạn sẽ sớm gặp ba khái niệm “nghe quen tai” nhưng dễ gây bối rối: **Monoid, Functor, Monad**.
- Monoid đến từ đại số trừu tượng.
- Functor đến từ category theory.
- Monad là “bước nhảy” kết nối cả hai.
Trong bài này, mình sẽ dẫn bạn đi từ Monoid → Functor → Monad, và cho thấy chúng liên hệ với nhau ra sao.
---
## 2. Monoid: gộp dữ liệu có cấu trúc
Monoid là một **tập hợp với phép toán kết hợp** và một **phần tử đơn vị**.
Ví dụ quen thuộc:
- Số nguyên với `+` và `0`.
- Danh sách với `@` và `[]`.
Trong OCaml, có thể mô tả bằng signature:
```ocaml
module type Monoid = sig
type t
val empty : t
val append : t -> t -> t
end
```
Monoid hữu ích để gộp dữ liệu: tính tổng, nối chuỗi, kiểm tra tất cả phần tử thỏa điều kiện (All/Any).
---
## 3. Functor: biến đổi giá trị trong “hộp”
Functor cho phép bạn **áp dụng hàm lên giá trị nằm trong cấu trúc** mà không cần phá hộp.
Ví dụ với `Option`:
```ocaml
let map_option f = function
| None -> None
| Some x -> Some (f x)
```
Luật của functor:
- `map id = id`
- `map (f ∘ g) = map f ∘ map g`
Functor giúp ta **biến đổi** dữ liệu, nhưng chưa cho phép thay đổi cấu trúc (chỉ bên trong hộp).
---
## 4. Monad: xâu chuỗi tính toán có context
Monad mở rộng functor bằng cách thêm hai phép:
- `return` (đưa giá trị vào hộp).
- `bind (>>=)` (lấy giá trị trong hộp, áp dụng hàm trả về hộp mới, rồi nối chuỗi).
Ví dụ với `Option`:
```ocaml
let return x = Some x
let (>>=) m f =
match m with
| None -> None
| Some x -> f x
```
Khi đó, ta có thể viết logic nhiều bước mà gọn gàng:
```ocaml
Some 3 >>= fun x ->
Some (x + 1) >>= fun y ->
if y mod 2 = 0 then Some (y / 2) else None
```
Kết quả: `Some 2`.
Nếu bất kỳ bước nào trả về `None`, toàn bộ tính toán dừng lại.
---
## 5. Monad, Functor và Monoid: mối quan hệ
Trong category theory:
- **Functor**: ánh xạ object và morphism giữa các category.
- **Monoid**: cấu trúc có phép gộp kết hợp và đơn vị.
- **Monad**: một **endofunctor** (từ category vào chính nó), cùng với hai phép tự nhiên:
- `unit` (return): `Id ⇒ T`
- `join` (flatten): `T(T A) ⇒ T A`
📌 Vì vậy: **Monad chính là một Monoid trong category của endofunctors**.
- Functor là nền tảng.
- Monad thêm cấu trúc monoid (return + bind).
### 🌐 Sơ đồ hóa mối quan hệ
```mermaid
graph TD
Monoid --> Functor
Functor --> Monad
Monoid -->|lift lên endofunctor| Monad
Monad -->|kết hợp| ContextualComputation[Chuỗi tính toán có context]
```
---
## 6. Ứng dụng thực tế của Monad
- **Option/Result Monad**: xử lý lỗi mà không cần `if` lặp lại.
- **List Monad**: sinh nhiều kết quả (Cartesian product, combinatorics).
- **State Monad**: quản lý trạng thái ngầm (parser, random generator).
- **Writer Monad**: tích log song song với kết quả.
- **Async Monad (Lwt/Async)**: viết code bất đồng bộ như code tuần tự.
---
## 7. Kết luận
- **Monoid** dạy ta cách gộp dữ liệu.
- **Functor** dạy ta cách biến đổi dữ liệu trong hộp.
- **Monad** kết hợp cả hai, để ta có thể xâu chuỗi các bước tính toán có context.
Trong lập trình hàm, Monad không chỉ là khái niệm trừu tượng từ category theory, mà còn là **mẫu thiết kế thực tế** để viết code ngắn gọn, an toàn và dễ đọc.
---
👉 Gợi ý tiếp theo: nếu bạn đã hiểu Monad, hãy thử nhìn sang **Applicative Functor** — nằm giữa Functor và Monad, rất hữu ích cho các trường hợp “song song” thay vì “tuần tự”.