Tôi viết câu trả lời của mình chủ yếu với Haskell trong đầu, mặc dù nhiều khái niệm áp dụng tốt như nhau cho các ngôn ngữ chức năng khác như Erlang, Lisp (s) và ML. Một số thậm chí áp dụng (trong một chừng mực nào đó) cho Ruby, Python, Perl và Javascript.
Làm thế nào để mọi người viết chương trình chức năng? Làm thế nào để họ bắt đầu?
Bằng cách viết các chức năng. Khi bạn đang lập trình chức năng, bạn hoặc đang viết main
hoặc bạn đang viết một hàm trợ giúp. Đôi khi mục tiêu chính của bạn có thể là viết một kiểu dữ liệu với các chức năng có liên quan khác nhau hoạt động trên nó.
Lập trình chức năng rất phù hợp với cả cách tiếp cận từ trên xuống và từ dưới lên. Haskell khuyến khích mạnh mẽ việc viết các chương trình của bạn bằng ngôn ngữ cấp cao, và sau đó chỉ cần xác định các chi tiết của thiết kế cấp cao của bạn. Xem minimum
, ví dụ:
minimum :: (Ord a) => [a] -> a
minimum xs = foldl1 min xs
Hàm tìm phần tử nhỏ nhất trong danh sách được viết đơn giản là một điểm ngang qua danh sách, sử dụng hàm min để so sánh từng phần tử với "bộ tích lũy" hoặc giá trị tối thiểu hiện tại.
Có các mẫu thiết kế cho các ngôn ngữ chức năng?
Có hai điều mà có thể được tương đương với "mẫu thiết kế", IMHO, chức năng bậc cao và monads . Hãy nói về cái trước. Các hàm bậc cao hơn là các hàm lấy các hàm khác làm đầu vào hoặc tạo ra các hàm làm đầu ra. Bất kỳ ngôn ngữ chức năng thường làm cho việc sử dụng nặng map
, filter
vàfold
(nếp gấp thường được gọi là "giảm"): ba hàm bậc cao rất cơ bản áp dụng một hàm cho một danh sách theo các cách khác nhau. Chúng thay thế nồi hơi cho các vòng lặp một cách đẹp. Truyền các hàm xung quanh làm tham số là một lợi ích cực kỳ mạnh mẽ để lập trình; rất nhiều "mẫu thiết kế" có thể được thực hiện đơn giản hơn bằng cách sử dụng các hàm bậc cao hơn, có thể tự tạo và có thể tận dụng thư viện tiêu chuẩn mạnh mẽ, có đầy đủ các chức năng hữu ích.
Monads là chủ đề "đáng sợ" hơn. Nhưng chúng không thực sự đáng sợ. Cách yêu thích của tôi khi nghĩ về các đơn nguyên là nghĩ về chúng như bao bọc một chức năng trong bong bóng và cho chức năng đó siêu năng lực (chỉ hoạt động bên trong bong bóng). Tôi có thể giải thích, nhưng thế giới không thực sự cần một sự tương tự đơn nguyên nào khác. Vì vậy, tôi sẽ chuyển sang các ví dụ nhanh. Giả sử tôi muốn sử dụng một "mẫu thiết kế" không đặc biệt. Tôi muốn chạy cùng một tính toán cho nhiều đầu vào khác nhau cùng một lúc. Tôi không muốn chọn chỉ một đầu vào, tôi muốn chọn tất cả. Đó sẽ là danh sách đơn nguyên:
allPlus2 :: [Int] -> [Int]
allPlus2 xs = do x <- xs
return (x + 2)
Bây giờ, cách thức thành ngữ để thực hiện điều này thực sự là map
, nhưng để minh họa, bạn có thể thấy cách danh sách đơn vị cho phép tôi viết một hàm trông giống như nó hoạt động trên một giá trị, nhưng lại có siêu năng lực để hoạt động trên mọi yếu tố trong một danh sách? Các siêu năng lực khác bao gồm thất bại, trạng thái, tương tác với "thế giới bên ngoài" và thực thi song song. Những siêu năng lực này rất mạnh và hầu hết các ngôn ngữ lập trình cho phép các chức năng với siêu năng lực lan tràn khắp nơi. Hầu hết mọi người nói rằng Haskell hoàn toàn không cho phép những siêu năng lực này, nhưng thực sự, Haskell chỉ chứa chúng trong các đơn nguyên để tác dụng của chúng có thể bị hạn chế và quan sát.
tl; dr Grokking các hàm và đơn vị bậc cao hơn là Haskell tương đương với các mẫu thiết kế mò mẫm. Khi bạn tìm hiểu các khái niệm Haskell này, bạn bắt đầu nghĩ "các mẫu thiết kế" chủ yếu là các cách giải quyết rẻ tiền để mô phỏng sức mạnh của Haskell.
Là các phương pháp như lập trình cực đoan hoặc phát triển nhanh có thể áp dụng cho các ngôn ngữ chức năng?
Tôi không thấy bất cứ điều gì ràng buộc các chiến lược quản lý này với bất kỳ mô hình lập trình nào. Như phynfo đã nêu, lập trình chức năng thực tế buộc bạn phải thực hiện phân rã chức năng, phá vỡ một vấn đề lớn thành các bài toán con, vì vậy các cột mốc nhỏ phải là một miếng bánh. Có các công cụ như QuickCheck và Zeno để kiểm tra hoặc thậm chí chứng minh các thuộc tính về các chức năng bạn viết.