15

Nhiều lần, tôi đã đi qua các tuyên bố của biểu mẫu X không/không soạn thảo tốt.Điều gì có ý nghĩa đối với một điều gì đó để "sáng tác tốt"?

tôi có thể nhớ vài trường hợp mà tôi đã đọc gần đây:

  • Macros không soạn tốt (bối cảnh: clojure)
  • Locks không soạn tốt (bối cảnh: clojure)
  • Lập trình bắt buộc không sáng tác tốt ... vv

Tôi muốn hiểu ý nghĩa của khả năng tổng hợp về thiết kế/đọc/viết mã? Ví dụ sẽ tốt đẹp.

+3

bản sao có thể có của [Tính tổng hợp có ý nghĩa gì trong ngữ cảnh lập trình hàm?] (Http://stackoverflow.com/questions/2887013/what-does-composability-mean-in-context-of-functional- lập trình) – missingfaktor

Trả lời

10

Chức năng "Soạn thảo" về cơ bản chỉ có nghĩa là gắn hai hoặc nhiều hàm lại với nhau để tạo một hàm lớn kết hợp chức năng của chúng theo cách hữu ích. Về cơ bản, bạn xác định một chuỗi các hàm và đường ống kết quả của từng cái vào phần tiếp theo, cuối cùng đưa ra kết quả của toàn bộ quá trình. Clojure cung cấp chức năng comp để thực hiện việc này cho bạn, bạn cũng có thể làm điều đó bằng tay.

Các chức năng mà bạn có thể kết nối với các chức năng khác theo cách sáng tạo hữu ích hơn nói chung so với các chức năng mà bạn chỉ có thể gọi trong một số điều kiện nhất định. Ví dụ: nếu chúng tôi không có chức năng last và chỉ có các hàm danh sách Lisp truyền thống, chúng tôi có thể dễ dàng xác định last(def last (comp first reverse)). Nhìn vào đó - chúng tôi thậm chí không cần phải defn hoặc đề cập đến bất kỳ đối số, bởi vì chúng tôi chỉ piping kết quả của một trong những chức năng khác. Điều này sẽ không hoạt động nếu, ví dụ: reverse đã thực hiện tuyến đường bắt buộc để sửa đổi trình tự tại chỗ. Macro cũng có vấn đề vì bạn không thể chuyển chúng thành các hàm như comp hoặc apply.

+1

Ví dụ về các macro không soạn thảo tốt. Nói rằng chúng tôi muốn làm một cái gì đó như thế này. (giảm và [true true true true]). Thật không may bởi vì và là một vĩ mô, chúng tôi không thể vượt qua nó để giảm. – Glen

2

Thành phần (trong ngữ cảnh bạn mô tả ở cấp chức năng) thường là khả năng nạp một hàm vào một hàm khác một cách sạch sẽ và không cần xử lý trung gian. Như một ví dụ về thành phần là trong std :: cout trong C++:

cout < < mỗi < < mục < < liên kết < < trên;

Đó là ví dụ đơn giản về bố cục không thực sự "trông" như bố cục.

Ví dụ khác có biểu mẫu rõ ràng hơn là hợp thành:

foo (thanh (baz()));

Wikipedia Link

phần rất hữu ích để có thể đọc và chặt, tuy nhiên chaining bộ sưu tập lớn các chức năng lồng vào nhau mà có khả năng có thể trở lại các mã lỗi hoặc dữ liệu rác có thể nguy hiểm (đây là lý do tại sao nó là tốt nhất để giảm thiểu mã lỗi hoặc trả lại rỗng Giá trị.)

Cung cấp chức năng của bạn sử dụng ngoại lệ, hoặc trả lại null objects bạn có thể giảm thiểu yêu cầu phân nhánh (nếu) về lỗi và tối đa hóa tiềm năng tổng hợp của mã của bạn.


là một vấn đề riêng biệt (chứ không phải những gì bạn đang yêu cầu, nhưng nó chia sẻ tên). Nó là một trong những ngăn chặn để lấy được hệ thống phân cấp đối tượng như trái ngược với thừa kế trực tiếp.

2

"Bang for the Buck" - sáng tác tốt ngụ ý tỷ lệ biểu đạt cao trên mỗi quy tắc thành phần. Mỗi macro giới thiệu quy tắc sáng tác của riêng mình. Mỗi cấu trúc dữ liệu tùy chỉnh đều giống nhau. Chức năng, đặc biệt là những người sử dụng cấu trúc dữ liệu chung có ít quy tắc hơn.

Chuyển nhượng và các tác dụng phụ khác, đặc biệt là wrt concurrency có nhiều quy tắc hơn.

2

Suy nghĩ về thời điểm bạn viết hàm hoặc phương thức. Bạn tạo một nhóm chức năng để thực hiện một tác vụ cụ thể. Khi làm việc trong một ngôn ngữ hướng đối tượng, bạn tập hợp hành vi của bạn xung quanh các hành động mà bạn nghĩ rằng một thực thể riêng biệt trong hệ thống sẽ thực hiện. Các chương trình chức năng tách khỏi điều này bằng cách khuyến khích các tác giả nhóm chức năng theo một trừu tượng. Ví dụ, thư viện Clojure Ring bao gồm một nhóm trừu tượng bao gồm định tuyến trong các ứng dụng web.

Vòng có thể phối hợp trong đó các hàm mô tả đường dẫn trong hệ thống (tuyến đường) có thể được nhóm thành các hàm bậc cao hơn (ở giữa). Thực tế, Clojure rất năng động, có thể (và bạn được khuyến khích) đưa ra các mẫu tuyến đường có thể được tạo động trong thời gian chạy. Đây là bản chất của composablilty, thay vì đưa ra các mẫu giải quyết một vấn đề nhất định, bạn tập trung vào các mẫu tạo ra các giải pháp cho một lớp nhất định của vấn đề. Nhà xây dựng và trình tạo mã chỉ là hai trong số các mẫu phổ biến được sử dụng trong lập trình hàm. Lập trình hàm là nghệ thuật của các mẫu tạo ra các mẫu khác (v.v ...).

Ý tưởng là giải quyết vấn đề ở cấp cơ bản nhất của nó rồi đưa ra các mẫu hoặc nhóm các hàm mức thấp nhất giải quyết vấn đề. Khi bạn bắt đầu thấy các mẫu ở cấp độ thấp nhất bạn đã phát hiện ra bố cục. Khi mọi người khám phá các mẫu đơn đặt hàng thứ hai trong các nhóm chức năng, họ có thể bắt đầu thấy cấp độ thứ ba. Và cứ như vậy ...

1

Trong ngữ cảnh của clojure, this comment giải quyết các khía cạnh nhất định của tính tương thích. Nói chung, nó dường như xuất hiện khi các đơn vị của hệ thống làm một điều tốt, không yêu cầu các đơn vị khác hiểu nội bộ của nó, tránh các tác dụng phụ, và chấp nhận và trả về các cấu trúc dữ liệu phổ biến của hệ thống. Tất cả những điều trên có thể được nhìn thấy trong ví dụ C++ của M2tM.

3

Thành phần trong lập trình có nghĩa là lắp ráp các phần lớn hơn từ những phần nhỏ hơn.

  • Thành phần của hàm đơn nhất tạo ra một hàm đơn nhất phức tạp hơn bằng cách chuỗi các hàm đơn giản hơn.
  • Thành phần cấu trúc dòng điều khiển đặt các cấu trúc dòng điều khiển bên trong các cấu trúc dòng điều khiển khác.
  • Thành phần cấu trúc dữ liệu kết hợp nhiều cấu trúc dữ liệu đơn giản thành một cấu trúc phức tạp hơn.

Lý tưởng nhất, đơn vị sáng tác hoạt động như một đơn vị cơ bản và bạn là người lập trình không cần phải biết sự khác biệt. Nếu mọi thứ thiếu lý tưởng, nếu một cái gì đó không sáng tác tốt, chương trình soạn thảo của bạn có thể không có hành vi kết hợp (dự định) của từng phần riêng lẻ của nó.

Giả sử tôi có một số mã C đơn giản.

void run_with_resource(void) { 
    Resource *r = create_resource(); 
    do_some_work(r); 
    destroy_resource(r); 
}

C tạo điều kiện cho lập luận về lưu lượng điều khiển ở mức chức năng.Tôi không phải quan tâm đến những gì thực sự xảy ra bên trong do_some_work(); Tôi biết chỉ bằng cách nhìn vào hàm nhỏ này mỗi lần một tài nguyên được tạo ra trên dòng 2 với create_resource(), nó cuối cùng sẽ bị phá hủy trên dòng 4 bởi destroy_resource().

Vâng, không hoàn toàn. Điều gì nếu create_resource() mua lại một khóa và destroy_resource() giải phóng nó? Sau đó, tôi phải lo lắng về việc liệu do_some_work có được cùng một khóa, điều này có thể ngăn chặn chức năng hoàn thành hay không. Điều gì sẽ xảy ra nếu do_some_work() gọi longjmp() và bỏ qua toàn bộ chức năng của tôi? Cho đến khi tôi biết những gì diễn ra trong do_some_work(), tôi sẽ không thể dự đoán được luồng điều khiển của hàm của tôi. Chúng tôi không còn sáng tác nữa: chúng tôi không còn có thể phân tích chương trình thành nhiều phần, lý do về các bộ phận độc lập và đưa kết luận của chúng tôi trở lại toàn bộ chương trình. Điều này làm cho việc thiết kế và gỡ lỗi trở nên khó khăn hơn nhiều và đó là lý do tại sao mọi người quan tâm liệu có điều gì đó sáng tác hay không.

1

composability, áp dụng cho các chức năng, có nghĩa là các chức năng có kích thước nhỏ và rõ ràng, do đó dễ dàng tích hợp vào các chức năng khác (tôi đã thấy ý tưởng này trong cuốn sách "niềm vui của clojure")

khái niệm này có thể áp dụng cho những thứ khác được cho là được sáng tác thành một thứ khác.

mục đích tính tương thích được tái sử dụng. ví dụ, một chức năng nổi xây dựng (composable) là dễ dàng hơn để tái sử dụng

macro không phải là nổi composable bởi vì bạn không thể vượt qua chúng như thông số

khóa là tào lao vì bạn có thể 't thực sự cung cấp cho họ tên (xác định chúng tốt) hoặc tái sử dụng chúng. bạn chỉ cần thực hiện chúng tại địa chỉ

ngôn ngữ mệnh lệnh không phải là composable vì (một số trong số đó, ít nhất) không có đóng cửa. nếu bạn muốn chức năng được truyền dưới dạng tham số, bạn sẽ bị hỏng. bạn phải xây dựng một đối tượng và vượt qua điều đó; từ chối trách nhiệm đây: ý tưởng cuối cùng này tôi không hoàn toàn bị thuyết phục là đúng, do đó nghiên cứu thêm trước khi dùng nó cho các cấp

một ý tưởng trên ngôn ngữ bắt buộc là họ không sáng tác tốt vì chúng ám chỉ bang (từ wikipedia knowledgebase :) "Lập trình bắt buộc - mô tả tính toán theo các câu lệnh thay đổi trạng thái chương trình").

trạng thái không kết hợp tốt vì mặc dù bạn đã đưa ra "thứ gì đó" cụ thể trong đầu vào, rằng "cái gì đó" tạo ra đầu ra theo trạng thái của nó. trạng thái nội tại khác nhau, hành vi khác nhau. và do đó bạn có thể nói lời tạm biệt với những gì bạn mong đợi xảy ra.

với trạng thái, bạn phụ thuộc nhiều vào việc biết trạng thái hiện tại của đối tượng là ... nếu bạn muốn dự đoán hành vi của nó. nhiều thứ để giữ lại trong tâm trí của bạn, ít composable (nhớ cũng xác định hoặc "nhỏ và đơn giản", như trong "dễ sử dụng"?)

ps: suy nghĩ của clojure học tập , Huh ? điều tra ...? tốt cho bạn !: P

Các vấn đề liên quan