Thuyết minh về tổ hợp cho người lao động


93

Bộ tổ hợp là gì ??

Nó có phải là "một hàm hoặc định nghĩa không có biến tự do" (như được định nghĩa trên SO) không?

Hoặc như thế nào về điều này: theo John Hughes trong bài báo nổi tiếng của anh ấy trên Arrows, "tổ hợp là một hàm tạo ra các đoạn chương trình từ các đoạn chương trình" , điều này rất thuận lợi vì "... lập trình viên sử dụng tổ hợp tạo ra phần lớn các lập trình tự động, thay vì viết từng chi tiết bằng tay ". Anh ấy tiếp tục nói điều đó mapfilterlà hai ví dụ phổ biến của các tổ hợp như vậy.

Một số tổ hợp phù hợp với định nghĩa đầu tiên:

  • S
  • K
  • Y
  • những người khác từ To Mock a Mockingbird (Tôi có thể nhầm - Tôi chưa đọc cuốn sách này)

Một số tổ hợp phù hợp với định nghĩa thứ hai:

  • bản đồ
  • bộ lọc
  • gấp / giảm (có lẽ)
  • bất kỳ >> =, soạn thư, fmap ?????

Tôi không quan tâm đến định nghĩa đầu tiên - những định nghĩa đó sẽ không giúp tôi viết một chương trình thực sự (+1 nếu bạn thuyết phục tôi rằng tôi sai). Xin hãy giúp tôi hiểu định nghĩa thứ hai . Tôi nghĩ bản đồ, bộ lọc và thu nhỏ rất hữu ích: chúng cho phép tôi lập trình ở cấp độ cao hơn - ít lỗi hơn, mã ngắn hơn và rõ ràng hơn. Dưới đây là một số câu hỏi cụ thể của tôi về tổ hợp:

  1. Các ví dụ khác về các tổ hợp như bản đồ, bộ lọc là gì?
  2. Ngôn ngữ lập trình thường thực hiện những tổ hợp nào?
  3. Làm cách nào để tổ hợp có thể giúp tôi thiết kế một API tốt hơn?
  4. Làm cách nào để thiết kế tổ hợp hiệu quả?
  5. Các tổ hợp tương tự như trong một ngôn ngữ phi chức năng (chẳng hạn như Java), hoặc những ngôn ngữ này sử dụng những gì thay cho các tổ hợp?

Cập nhật

Cảm ơn @CA McCann, giờ đây tôi đã hiểu rõ hơn phần nào về các tổ hợp. Nhưng một câu hỏi vẫn là một điểm mấu chốt đối với tôi:

Sự khác biệt giữa một chương trình chức năng được viết với và một chương trình được viết không có, sử dụng nhiều tổ hợp là gì?

Tôi nghi ngờ câu trả lời là phiên bản hạng nặng tổ hợp ngắn hơn, rõ ràng hơn, tổng quát hơn, nhưng tôi sẽ đánh giá cao một cuộc thảo luận sâu hơn, nếu có thể.

Tôi cũng đang tìm kiếm thêm các ví dụ và giải thích về các tổ hợp phức tạp (tức là phức tạp hơn fold) trong các ngôn ngữ lập trình phổ biến.


4
Tôi xem xét bản đồ / bộ lọc / gấp các Hàm bậc cao hơn và tôi sử dụng chúng mọi lúc. Tôi vẫn không biết tổ hợp là gì.

1
@pst - Tôi sẽ đồng ý 5 ngày trước, nhưng bây giờ tôi không thể tranh luận với John Hughes
Matt Fenwick

Câu trả lời:


93

Tôi không quan tâm đến định nghĩa đầu tiên - những định nghĩa đó sẽ không giúp tôi viết một chương trình thực sự (+1 nếu bạn thuyết phục tôi rằng tôi sai). Xin hãy giúp tôi hiểu định nghĩa thứ hai. Tôi nghĩ bản đồ, bộ lọc và thu nhỏ rất hữu ích: chúng cho phép tôi lập trình ở cấp độ cao hơn - ít lỗi hơn, mã ngắn hơn và rõ ràng hơn.

Hai định nghĩa về cơ bản là giống nhau. Đầu tiên là dựa trên định nghĩa chính thức và các ví dụ bạn đưa ra là các tổ hợp nguyên thủy - các khối xây dựng nhỏ nhất có thể. Họ có thể giúp bạn viết một chương trình thực trong chừng mực, với họ, bạn có thể xây dựng các tổ hợp phức tạp hơn. Hãy coi các tổ hợp như S và K là ngôn ngữ máy của một "máy tính tổ hợp" giả định. Tất nhiên, máy tính thực tế không hoạt động theo cách đó, vì vậy trong thực tế, bạn thường sẽ có các hoạt động cấp cao hơn được triển khai ở hậu trường theo những cách khác, nhưng nền tảng khái niệm vẫn là một công cụ hữu ích để hiểu ý nghĩa của những hoạt động cấp cao hơn đó. các hoạt động.

Định nghĩa thứ hai bạn đưa ra là không chính thức hơn và về việc sử dụng các tổ hợp phức tạp hơn, dưới dạng các hàm bậc cao hơn kết hợp các hàm khác theo nhiều cách khác nhau. Lưu ý rằng nếu các khối xây dựng cơ bản là các tổ hợp nguyên thủy ở trên, thì mọi thứ được xây dựng từ chúng đều là một hàm bậc cao hơn và cũng là một tổ hợp. Tuy nhiên, trong một ngôn ngữ mà các nguyên hàm khác tồn tại, bạn có sự phân biệt giữa những thứ có hoặc không phải là chức năng, trong trường hợp đó, tổ hợp thường được định nghĩa là một hàm thao tác các chức năng khác theo cách chung, thay vì hoạt động trên bất kỳ chức năng mọi thứ một cách trực tiếp.

Các ví dụ khác về các tổ hợp như bản đồ, bộ lọc là gì?

Quá nhiều để liệt kê! Cả hai đều biến đổi một hàm mô tả hành vi trên một giá trị đơn lẻ thành một hàm mô tả hành vi trên toàn bộ tập hợp. Bạn cũng có thể có các hàm chỉ chuyển đổi các hàm khác, chẳng hạn như soạn chúng từ đầu đến cuối hoặc tách và kết hợp các đối số. Bạn có thể có các tổ hợp biến các hoạt động một bước thành các hoạt động đệ quy tạo ra hoặc sử dụng các bộ sưu tập. Hoặc tất cả những thứ khác, thực sự.

Ngôn ngữ lập trình thường thực hiện những tổ hợp nào?

Điều đó sẽ thay đổi khá nhiều. Có tương đối ít các tổ hợp hoàn toàn chung chung - chủ yếu là các tổ hợp nguyên thủy được đề cập ở trên - vì vậy trong hầu hết các trường hợp, các tổ hợp sẽ có một số nhận thức về bất kỳ cấu trúc dữ liệu nào đang được sử dụng (ngay cả khi những cấu trúc dữ liệu đó được xây dựng từ các tổ hợp khác), trong đó trường hợp thường có một số ít các tổ hợp "hoàn toàn chung chung" và sau đó là bất kỳ hình thức chuyên biệt nào mà ai đó quyết định cung cấp. Có một số trường hợp vô lý trong đó (các phiên bản tổng quát phù hợp của) bản đồ, màn hình gập và mở ra là đủ để làm hầu hết mọi thứ bạn có thể muốn.

Làm cách nào để tổ hợp có thể giúp tôi thiết kế một API tốt hơn?

Chính xác như bạn đã nói, bằng cách suy nghĩ về các hoạt động cấp cao và cách chúng tương tác, thay vì các chi tiết cấp thấp.

Hãy nghĩ về mức độ phổ biến của các vòng lặp kiểu "for each" đối với các bộ sưu tập, cho phép bạn tóm tắt các chi tiết của việc liệt kê một bộ sưu tập. Đây chỉ là các thao tác ánh xạ / màn hình đầu tiên trong hầu hết các trường hợp và bằng cách tạo một tổ hợp (thay vì cú pháp tích hợp), bạn có thể thực hiện những việc như lấy hai vòng lặp hiện có và kết hợp trực tiếp chúng theo nhiều cách - lồng cái này vào bên trong cái kia, làm cái này đến cái kia, và cứ thế - bằng cách chỉ áp dụng một bộ tổ hợp, thay vì tung hứng cả đống mã xung quanh.

Làm cách nào để thiết kế tổ hợp hiệu quả?

Trước tiên, hãy nghĩ xem các thao tác nào có ý nghĩa trên bất kỳ dữ liệu nào mà chương trình của bạn sử dụng. Sau đó, hãy suy nghĩ về cách các hoạt động đó có thể được kết hợp một cách có ý nghĩa theo những cách chung, cũng như cách các hoạt động có thể được chia thành các phần nhỏ hơn được kết nối lại với nhau. Điều chính là làm việc với các phép biến đổihoạt động , không phải các hành động trực tiếp . Khi bạn có một chức năng chỉ thực hiện một số chức năng phức tạp theo cách không rõ ràng và chỉ tạo ra một số loại kết quả được tiêu hóa trước, bạn không thể làm gì nhiều với điều đó. Để lại kết quả cuối cùng cho mã sử dụng các tổ hợp - bạn muốn những thứ đưa bạn từ điểm A đến điểm B, không phải những thứ mong đợi là bắt đầu hoặc kết thúc của một quy trình.

Các tổ hợp tương tự như trong một ngôn ngữ phi chức năng (chẳng hạn như Java), hoặc những ngôn ngữ này sử dụng những gì thay cho các tổ hợp?

Ahahahaha. Bạn nên hỏi, vì các đối tượng thực sự là những thứ có bậc cao hơn ngay từ đầu - chúng có một số dữ liệu, nhưng chúng cũng thực hiện một loạt các hoạt động và khá nhiều thứ tạo nên thiết kế OOP tốt được tóm gọn lại thành "các đối tượng nên thường hoạt động giống như tổ hợp, không phải cấu trúc dữ liệu ".

Vì vậy, có lẽ câu trả lời tốt nhất ở đây là thay vì những thứ giống như tổ hợp, chúng sử dụng các lớp với nhiều phương thức getter và setter hoặc các trường công khai, và logic chủ yếu bao gồm thực hiện một số hành động không rõ ràng, được xác định trước.


Câu trả lời chính xác! Hãy xem tôi có hiểu không - tổ hợp không phải là đặc biệt, mà là một phần không thể thiếu trong việc xây dựng một hệ thống phần mềm có thể bảo trì? Tôi vẫn đang cố đọc câu lệnh "đoạn chương trình" của Hughes, trong ngữ cảnh bài đăng của bạn.
Matt Fenwick

@Matt Fenwick: Tôi khá chắc rằng anh ấy chỉ đang sử dụng "các đoạn chương trình" để chỉ loại phép biến đổi / phép toán mà tôi đang nói đến, đặc biệt nếu điều đó đang nói về "Mũi tên", điều này càng nhấn mạnh cách tiếp cận đó mạnh mẽ hơn. Ngoài ra, tôi sẽ không nói chính xác về việc xây dựng các hệ thống có thể bảo trì - nói thêm về việc xây dựng các hệ thống có tính mô-đun cao và được tách rời theo một cách cụ thể , với những lợi ích đi kèm.
CA McCann

Bạn có biết bất kỳ tài nguyên tốt nào để đọc về cách sử dụng thực tế của tổ hợp không? Cảm ơn nhiều!
Matt Fenwick

@Matt Fenwick: Không có gì cụ thể cho điều đó ngoài đầu tôi, xin lỗi. Tuy nhiên, nó có xu hướng là một cách tiếp cận tự nhiên đối với các chương trình được viết theo phong cách rất chức năng, vì vậy chỉ cần dành một chút thời gian với các ngôn ngữ khuyến khích mạnh mẽ điều đó (ví dụ: Haskell hoặc Clojure) và xem cách mã rõ ràng và dễ hiểu được viết bằng ngôn ngữ đó , là một cách khá tốt để tìm hiểu phong cách.
CA McCann
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.