2011-02-10 24 views
10

Tôi mới đến Clojure và tìm thấy chân biển của tôi. Tôi đã tự hỏi liệu nó được coi là thực hành tốt hay xấu, từ một quan điểm lập trình chức năng, để đặt các hàm vào bản đồ Clojure và sau đó chuyển các bản đồ đó xung quanh như các đối tượng bán, như thường được thực hiện trong JavaScript. Giải thích cũng sẽ được đánh giá cao.Có nên đặt các chức năng trong bản đồ Clojure như JavaScript không?

+0

Tôi vừa hỏi một câu hỏi chung liên quan đến điều này mà bạn có thể thấy hữu ích: http://stackoverflow.com/questions/4969593/achieving-polymorphism-in-functional-programming – mikera

+0

Cảm ơn liên kết đó – dan

Trả lời

7

Đa phương tiện của Clojure về cơ bản là bản đồ của các hàm, do đó, không, nó không phải là một ý tưởng tồi chút nào.

6

Nó sẽ là xấu vì nhiều lý do:

  1. Đó là không cần thiết - Trong JavaScript, chúng tôi đang làm nó để sử dụng bản đồ đơn giản như các đối tượng Java như thế nào. Trong Clojure, nếu bạn thực sự muốn làm như vậy, bạn có thể sử dụng đối tượng Java thực tế thông qua Java interop.
  2. Cho dù bạn đang đặt chức năng vào bản đồ hay đang sử dụng đối tượng Java thực, bạn đang làm lập trình hướng đối tượng trong môi trường ngôn ngữ được thiết kế cho lập trình hàm. Mối quan tâm đầu tiên đi kèm với nó là mã của bạn chỉ sẽ không khớp với số. Nó trông kỳ lạ, vụng về và thậm chí có thể quá phức tạp trong Clojure. Tại thời điểm này, tôi không nói rằng OOP là nhất thiết phải xấu, chỉ là nó là tốt hơn để viết OOP trong các ngôn ngữ được thiết kế cho nó.
  3. Điểm quan trọng nhất đối với kiểu mã hóa như vậy là chương trình giống như OOP chắc chắn sẽ dựa vào các đối tượng có trạng thái nào đó và các hàm thành viên của chúng (giống như các phương thức) thay đổi trạng thái đó. Nếu bạn đang sử dụng nhà nước, sau đó chức năng của bạn không phải là tinh khiết và bạn không thể sử dụng tất cả các goodness chức năng như song song dễ dàng.

Câu chuyện dài, nếu bạn đang sử dụng Clojure để làm OOP, bạn sẽ chỉ cảm thấy khó chịu. Bạn có thể làm OOP dễ dàng hơn bằng nhiều ngôn ngữ khác, như Groovy nói. Nếu bạn muốn sử dụng Clojure làm điều đó theo cách chức năng.

Cho đến nay tôi đã viết không làm điều đó và tại sao không làm điều đó. Bây giờ bạn có thể hỏi tôi: Vì vậy, làm thế nào tôi nên viết các chức năng trong Clojure?

Viết các hàm mang cấu trúc dữ liệu của bạn (ví dụ: bản đồ, danh sách, đối tượng ... bất kỳ) làm thông số. Vì vậy, thay vì:

foo.bar(); 

Bạn sẽ xác định nó như thế này:

(defn bar [foo] 
    ;stuff 
    ) 

Và gọi nó là như thế này:

(bar foo) 

Bây giờ, đối với một chức năng tinh khiết bar, foo đối tượng là không thay đổi sau khi đánh giá chức năng và bạn không có trạng thái chia sẻ của đối tượng để lo lắng về việc liệu bạn có quyết định song song mã của mình hay không, cái mà bạn sẽ có nếu bạn đang làm những điều theo cách OOP.

Ngoài ra, nó có thể trông giống như một sự khác biệt nhỏ, nhưng lưu ý rằng định nghĩa hàm bar là một thực thể hoàn toàn độc lập với cấu trúc dữ liệu foo. Ngoài ra, foo chỉ chứa dữ liệu, không phải hành vi - tất cả các hành vi đều có trong hàm. Sự tách biệt này mang lại cho bạn sự tự do lớn hơn nhiều khi viết mã.

+0

Là một hệ quả của những gì bạn đang nói rằng một trong những cũng có thể mã trong _JavaScript_ một cách hoàn toàn chức năng? Trong trường hợp đó, tôi tự hỏi tại sao mô hình O-O-esque lại chiếm ưu thế trong JavaScript. – dan

+0

Có. Có thể lập trình chức năng bằng JavaScript. Tôi nghi ngờ rằng mô hình OO đã được nhập vào JavaScript dưới ảnh hưởng của các ngôn ngữ chính thống khác như Java. Ngoài ra, hãy xem xét rằng một số lý do chính đáng để sử dụng FP, như khả năng pararelization dễ dàng, không áp dụng được cho JavaScript, vì dù sao thì nó cũng đơn luồng. –

+0

@dan: Ồ, và thực tế là một số trình duyệt có chức năng gọi stack khá hạn chế thực sự giết bất kỳ khả năng nào để sử dụng đệ quy hợp lý. Đó là một lý do chính đáng để không sử dụng FP trong JavaScript. –

2

Nếu bạn thực sự cần lập trình hướng đối tượng trong Clojure, có một số cách để thực hiện việc này.

Cách thứ nhất là sử dụng các dòng macro deftype, defrecorddefprotocol.

Cách thứ hai là sử dụng đa phương thức, kết hợp với bản đồ hoặc loại bản ghi để lưu trữ dữ liệu.

Cách thứ ba là sử dụng mẫu thiết kế chung như được nêu trong Steve Yegge hoặc có thể tìm thấy phần giới thiệu cụ thể khác của Clojure trong sách của Chris Houser và Michael Fogus The Joy of Clojure.

Cách tiếp cận thứ ba rất giống với những gì bạn mong đợi thấy trong JavaScript, và cách tiếp cận đầu tiên, trong khi không được coi là OOP theo nghĩa truyền thống, là phổ biến nhất trong Clojure thành ngữ "hiện đại".

+0

Không có cách tiếp cận nào bạn liệt kê liên quan đến việc đặt đối tượng hàm trong bản đồ/đối tượng để mô phỏng các phương thức. Tất cả chúng dường như là về đối tượng với dữ liệu tách biệt với các hàm có hành vi. –

+0

trong khi không phải là những gì các poster ban đầu đã có trong tâm trí, giao thức chắc chắn làm phương pháp lưu trữ trong bản đồ. tôi có thể, tuy nhiên, là misremembering niềm vui của phần clojure. – apg

8

Làm điều đó, nếu nó làm cho mã của bạn ngắn hơn hoặc dễ hiểu hơn, hoặc kiểm tra hoặc gỡ lỗi.

Hoặc nếu bạn muốn. Tin tưởng phán xét của bạn.

4

Nó hoạt động - và theo một nghĩa nào đó là tự nhiên nếu bạn xem xét các chức năng như các đối tượng hạng nhất trong ngôn ngữ (như tất cả các lập trình viên chức năng nên!)

Tuy nhiên - nó cần được chăm sóc thật bởi vì những gì bạn đang về cơ bản làm là mã xen kẽ với dữ liệu. Nó giống như trộn mô hình dữ liệu của bạn với mã trình bày trong MVC. Có, có thể có một số tình huống mà nó có ý nghĩa nhưng nguyên tắc chung sẽ là để tránh nó.

Phong cách Tôi chậm rãi hội tụ về phía sau khoảng một năm Clojure là:

  • Một vài top-level refs/nguyên tử/VAR cho việc quản lý nhà nước rõ ràng có thể thay đổi
  • (tiếng tăm sang Rich Hickey!)
  • Cấu trúc dữ liệu lớn, lồng nhau trong các tham chiếu cấp cao nhất
  • Chức năng thuần túy để xử lý khá nhiều việc xử lý
  • Một vài chức năng kết thúc bằng! đối với những tác dụng phụ khó chịu đó, được sử dụng một cách tiết kiệm
  • Rất nhiều và nhiều thử nghiệm! Điều này thực sự quan trọng bởi vì với cách gõ động và cấu trúc dữ liệu rất linh hoạt, bạn cần kiểm tra khá nhiều giả định của mình
  • Java (thật đáng buồn!) Để tối ưu hóa các phần nhạy cảm của mã, thường được thực hiện bằng cách định nghĩa một lớp Java không thay đổi. cũng trong cấu trúc dữ liệu Clojure

Điều này giải quyết hầu hết mọi thứ dưới ánh mặt trời, điều tôi vẫn đang cố gắng tìm ra là cách tốt nhất để tạo các đối tượng có hành vi đa hình cao. lựa chọn chính tôi có thể thấy là:

  • Sử dụng giao thức với deftype/defrecord - hiệu suất cao, thành ngữ Clojure, nhưng bạn chỉ nhận được công văn duy nhất trên kiểu đó là không đủ đối với một số tình huống rất đa hình
  • Tạo chức năng mà cư xử theo một cách đa hình bởi nhiều macro/thành phần hàm bậc cao hơn - công trình, nhưng có thể rất phức tạp/phức tạp để duy trì
  • Đặt các hàm bên trong bản đồ! Có nó cảm thấy sai, nhưng nó hoạt động!

Vẫn chưa tìm ra cách nào để đi ..... nhưng tôi có linh cảm mà các chức năng có thể lẻn vào bản đồ nhiều hơn một chút trong tương lai ....

1

Không gian tên theo nghĩa đen là bản đồ của các hàm. Việc sử dụng chúng để tổ chức các chức năng của bạn trở nên đơn giản hơn nhiều. Tuy nhiên, nếu bạn gặp phải hạn chế về không gian tên cho trường hợp sử dụng của mình, bạn có thể cân nhắc việc đặt các hàm vào bản đồ.

Như thường lệ khi đi ra khỏi đường bị đánh đập, hãy chắc chắn suy nghĩ kỹ về lý do tại sao bạn không đi theo lộ trình rõ ràng.

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