---
# System prepended metadata

title: Làm quen với Monoid qua OCaml
tags: [Monoid]

---

# Làm quen với Monoid qua OCaml

## Monoid là gì?

Trong lập trình hàm và toán học, **Monoid** là một khái niệm đơn giản nhưng rất mạnh mẽ để mô tả cách gộp dữ liệu. Một Monoid gồm:

1. **Phép gộp** (append): một hàm kết hợp hai giá trị.
2. **Phần tử trung hoà** (empty): một giá trị không làm thay đổi kết quả khi gộp.

Điều kiện:

* **Tính kết hợp**: `(a ⋅ b) ⋅ c = a ⋅ (b ⋅ c)`
* **Phần tử trung hoà**: `empty ⋅ x = x ⋅ empty = x`

Ví dụ quen thuộc:

* `int` với phép cộng: `empty = 0`, `append = +`
* `bool` với `&&`: `empty = true` → kiểm tra "tất cả đều đúng".
* `bool` với `||`: `empty = false` → kiểm tra "ít nhất một đúng".

---

## Tại sao cần Monoid?

Monoid giúp ta viết các **hàm gộp tổng quát**. Thay vì viết riêng hàm `sum`, `product`, `all`, `any`, ta chỉ cần một hàm duy nhất:

```ocaml
let concat (type a) (module M : Monoid with type t = a) (xs : a list) : a =
  List.fold_left M.append M.empty xs
```

Ví dụ:

```ocaml
concat (module Sum) [1;2;3]        (* → 6 *)
concat (module All) [true; false]  (* → false *)
concat (module Any)  []            (* → false *)
```

---

## Ứng dụng thực tế

* **Xử lý log phân tán**: ghép log từ nhiều server → dùng Monoid nối list.
* **Tính tổng nhiều giá trị** (giá, điểm, đơn hàng...)
* **Kiểm tra tất cả điều kiện thoả mãn** → `All`
* **Kiểm tra có điều kiện nào đúng không** → `Any`
* **Lập trình song song/phân tán**: nhờ tính kết hợp, ta gộp theo từng cụm rồi ghép kết quả cuối.

---

## Cài đặt Monoid trong OCaml

```ocaml
module type Monoid = sig
  type t
  val empty : t
  val append : t -> t -> t
end

module Sum : Monoid with type t = int = struct
  type t = int
  let empty = 0
  let append = ( + )
end

module All : Monoid with type t = bool = struct
  type t = bool
  let empty = true
  let append = ( && )
end

module Any : Monoid with type t = bool = struct
  type t = bool
  let empty = false
  let append = ( || )
end
```

---

## Hàm `concat` tổng quát

```ocaml
let concat (type a) (module M : Monoid with type t = a) (xs : a list) : a =
  List.fold_left M.append M.empty xs
```

Ví dụ:

```ocaml
concat (module Sum) [1;2;3] = 6
concat (module All) [true; true] = true
concat (module Any) [false; true] = true
```

---

## Phân tích hành vi với list rỗng

| Monoid  | empty | `concat []` | Nghĩa                                             |
| ------- | ----- | ----------- | ------------------------------------------------- |
| Sum     | 0     | 0           | Tổng không có gì = 0                              |
| Product | 1     | 1           | Nhân không có gì = 1                              |
| All     | true  | true        | Mọi phần tử đúng trên tập rỗng = true             |
| Any     | false | false       | Có ít nhất một phần tử đúng trên tập rỗng = false |

---

## Tiếp theo?

* Viết thêm monoid cho list (nối list), chuỗi (nối string)...
* Thử kết hợp Monoid vào validate form, thống kê, log...
* Học sang `Functor`, `Applicative`, `Monad` sau khi đã hiểu rõ `concat`.
