Mặc dù đôi khi nó diễn đạt theo cách đó, lập trình chức năng - không ngăn chặn các tính toán trạng thái. Những gì nó làm là buộc các lập trình viên phải làm cho nhà nước rõ ràng.
Ví dụ: chúng ta hãy lấy cấu trúc cơ bản của một số chương trình bằng cách sử dụng hàng đợi bắt buộc (trong một số ngôn ngữ giả):
q := Queue.new();
while (true) {
if (Queue.is_empty(q)) {
Queue.add(q, producer());
} else {
consumer(Queue.take(q));
}
}
Cấu trúc tương ứng với cấu trúc dữ liệu hàng đợi chức năng (vẫn bằng ngôn ngữ bắt buộc, để giải quyết một sự khác biệt tại một thời điểm) sẽ giống như sau:
q := Queue.empty;
while (true) {
if (q = Queue.empty) {
q := Queue.add(q, producer());
} else {
(tail, element) := Queue.take(q);
consumer(element);
q := tail;
}
}
Vì hàng đợi bây giờ là bất biến, nên đối tượng không thay đổi. Trong mã giả này, q
chính nó là một biến; các bài tập q := Queue.add(…)
và q := tail
làm cho nó trỏ đến một đối tượng khác. Giao diện của các hàm hàng đợi đã thay đổi: mỗi hàm phải trả về đối tượng hàng đợi mới là kết quả của hoạt động.
Trong một ngôn ngữ chức năng thuần túy, tức là trong một ngôn ngữ không có tác dụng phụ, bạn cần phải làm cho tất cả các trạng thái rõ ràng. Vì nhà sản xuất và người tiêu dùng có lẽ đang làm gì đó, trạng thái của họ cũng phải có trong giao diện của người gọi ở đây.
main_loop(q, other_state) {
if (q = Queue.empty) {
let (new_state, element) = producer(other_state);
main_loop(Queue.add(q, element), new_state);
} else {
let (tail, element) = Queue.take(q);
let new_state = consumer(other_state, element);
main_loop(tail, new_state);
}
}
main_loop(Queue.empty, initial_state)
Lưu ý làm thế nào bây giờ mọi phần của nhà nước được quản lý rõ ràng. Các hàm thao tác hàng đợi lấy một hàng đợi làm đầu vào và tạo ra một hàng đợi mới làm đầu ra. Các nhà sản xuất và người tiêu dùng cũng vượt qua trạng thái của họ.
Lập trình đồng thời không phù hợp rất tốt trong lập trình chức năng, nhưng nó phù hợp rất tốt xung quanh lập trình chức năng. Ý tưởng là chạy một loạt các nút tính toán riêng biệt và để chúng trao đổi thông điệp. Mỗi nút chạy một chương trình chức năng và trạng thái của nó thay đổi khi nó gửi và nhận tin nhắn.
Tiếp tục ví dụ, vì có một hàng đợi duy nhất, nó được quản lý bởi một nút cụ thể. Người tiêu dùng gửi cho nút đó một thông điệp để có được một phần tử. Các nhà sản xuất gửi cho nút đó một thông điệp để thêm một phần tử.
main_loop(q) =
consumer->consume(q->take()) || q->add(producer->produce());
main_loop(q)
Ngôn ngữ được công nghiệp hóa của một người dùng mà được đồng thời hóa là Erlang . Học Erlang chắc chắn là con đường dẫn đến sự giác ngộ - về lập trình đồng thời.
Mọi người chuyển sang ngôn ngữ không có tác dụng phụ ngay bây giờ!
¹ Thuật ngữ này có nhiều ý nghĩa; Ở đây tôi nghĩ rằng bạn đang sử dụng nó để có nghĩa là lập trình mà không có tác dụng phụ, và đó là ý nghĩa tôi cũng đang sử dụng.
² Lập trình với trạng thái ngầm là lập trình bắt buộc ; định hướng đối tượng là một mối quan tâm hoàn toàn trực giao.
³ Viêm, tôi biết, nhưng tôi có nghĩa là nó. Chủ đề với bộ nhớ chia sẻ là ngôn ngữ lắp ráp của lập trình đồng thời. Truyền tin nhắn dễ hiểu hơn rất nhiều và việc thiếu tác dụng phụ thực sự tỏa sáng ngay khi bạn giới thiệu đồng thời.
⁴ Và điều này xuất phát từ một ai đó không phải là một fan hâm mộ của Erlang, nhưng vì lý do khác.