Làm thế nào để bạn thiết kế chương trình bằng Haskell hoặc các ngôn ngữ lập trình chức năng khác?


52

Tôi có một số kinh nghiệm trong các ngôn ngữ lập trình hướng đối tượng như c # hoặc ruby. Tôi biết cách thiết kế một chương trình theo phong cách hướng đối tượng, cách tạo các lớp và đối tượng và cách xác định quan hệ giữa chúng. Tôi cũng biết một số mẫu thiết kế.

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? Có các mẫu thiết kế cho các ngôn ngữ chức năng? 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?


1
câu hỏi liên quan: stackoverflow.com/questions/3077866/
Mạnh

Câu trả lời:


24

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 mainhoặ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 caomonads . 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, filterfold(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.


"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 nữa." - Chúng tôi luôn cần nhiều tương tự cho các đơn nguyên và của bạn là một trong những điều tốt nhất tôi đã thấy.
Adam Gent

1
Câu trả lời tuyệt vời, nhưng tôi nghĩ rằng cuộc thảo luận của bạn về các mẫu thiết kế là một chút sai lệch. Mặc dù bạn không cần các mẫu thiết kế theo kiểu OO / GOF trong Haskell - thực tế sẽ rất nực cười khi thử chúng - bản thân các mẫu chỉ đơn giản là cách cộng đồng truyền đạt giải pháp cho các loại vấn đề xuất hiện lặp đi lặp lại. Cộng đồng Haskell vẫn còn rất trẻ, vì vậy vẫn chưa có nhiều mẫu để nói, nhưng nếu bạn hỏi tôi ví dụ về các mẫu Haskell, tôi sẽ đề cập đến những thứ như GADT hoặc Arrowized FRP.
rtperson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.