Câu hỏi Clojure và các Lisps khác [đóng cửa]


Mục đích của câu hỏi của tôi là không phải để bắt đầu một cuộc chiến tranh lửa, mà là để xác định trong hoàn cảnh nào mỗi ngôn ngữ là "công cụ tốt nhất cho công việc".

Tôi đã đọc vài cuốn sách về Clojure (Lập trình Clojure, Clojure thực tế, Niềm vui của Clojurevà phiên bản Manning Early Access của Clojure trong hành động), và tôi nghĩ đó là một ngôn ngữ tuyệt vời. Tôi hiện đang đọc Let Over Lambda mà chủ yếu là giao dịch với các macro Common Lisp, và, nó cũng là một ngôn ngữ rất thú vị.

tôi là không phải một chuyên gia Lisp (nhiều người mới), nhưng gia đình ngôn ngữ này mê hoặc tôi, cũng như lập trình chức năng nói chung.

Ưu điểm của Clojure (và nhược điểm của "những người khác"):

  • Chạy trên JVM.

    • JVM là một môi trường ngôn ngữ hiệu năng cao, rất ổn định, đáp ứng khá tốt giấc mơ của Sun về "Viết một lần, chạy [gần như] ở bất cứ đâu". Tôi có thể viết mã trên Macbook Pro của tôi, biên dịch nó thành một tệp JAR thực thi, và sau đó chạy nó trên Linux và Microsoft Windows với ít thử nghiệm bổ sung.

    • JVM (Điểm phát sóng và khác) hỗ trợ thu thập rác chất lượng cao và biên dịch và tối ưu hóa ngay trong thời gian rất hiệu quả. Chỉ một vài năm trước đây, tôi đã viết mọi thứ phải chạy nhanh trong C, bây giờ tôi không ngần ngại làm như vậy trong Java.

    • Tiêu chuẩn, đơn giản, đa luồng mô hình. Lisp thường có một gói đa luồng tiêu chuẩn?

    • Phá vỡ sự đơn điệu của tất cả những dấu ngoặc đơn đó [], {}#{}, mặc dù các chuyên gia thường gặp Lisp có thể sẽ cho tôi biết rằng với các macro đọc, bạn có thể thêm chúng vào CL.

Nhược điểm của Clojure:

  • Chạy trên JVM.
    • Không có đệ quy đuôi hoặc tiếp tục. Lisp thường hỗ trợ tiếp tục? Đề án yêu cầu hỗ trợ cho cả hai, tôi tin.

Ưu điểm của người khác (Common Lisp, đặc biệt) (và nhược điểm của Clojure):

  • Các macro trình đọc có thể xác định người dùng.

  • Lợi thế khác?

Suy nghĩ? Sự khác biệt khác?


76


gốc


cá nhân tôi thích một loại dấu ngoặc đơn;) trông giống như mã "sạch hơn" - Moe
Từ những gì tôi đọc trong danh sách Ưu điểm của bạn, tôi có thể bạn cũng có thể thích Erlang www.erlang.org - Peer Stritzinger
Clojure hỗ trợ đệ quy đuôi rõ ràng thông qua biểu mẫu đặc biệt "tái diễn". Điều này cho phép bạn để có được tất cả những lợi ích của đệ quy đuôi cung cấp cho bạn một cách rõ ràng yêu cầu nó (ngoại lệ duy nhất là nó hiện không hỗ trợ đuôi nhau tham khảo giữa nhiều chức năng). - mikera
Clojure cũng hỗ trợ sự tiếp tục, ít nhất là theo nghĩa "kiểu chuyển tiếp tiếp tục". Bạn đúng là nó không có tiếp tục lớp học đầu tiên. xem stackoverflow.com/questions/1173133/continuations-in-clojure - mikera
@mikera: Đệ quy đệ quy trên một hàm. Hai chức năng gọi nhau phải được thực hiện với "trampolining", đó là loại kludgy (nhưng thanh lịch theo cách riêng của nó :-)). - Ralph


Các câu trả lời:


Danh sách cá nhân của tôi về lý do thích Clojure để Lisps khác (ps.s. Tôi vẫn nghĩ rằng tất cả Lisps là tuyệt vời!):

  • Chạy trên JVM - do đó được tự động truy cập vào kỹ thuật tuyệt vời trong chính JVM (các thuật toán thu gom rác tiên tiến, tối ưu hóa HotSpot JIT, v.v.)

  • Khả năng tương tác Java rất tốt - cung cấp khả năng tương thích với phạm vi rộng lớn của các thư viện trong hệ sinh thái ngôn ngữ Java / JVM. Tôi đã sử dụng Clojure như một ngôn ngữ "keo" để kết nối các thư viện Java khác nhau với hiệu quả tốt. Vì tôi cũng phát triển rất nhiều mã Java, điều hữu ích đối với tôi là Clojure tích hợp tốt với công cụ Java (ví dụ: tôi sử dụng Maven, Eclipse với plugin Ngược chiều kim đồng hồ để phát triển Clojure của tôi)

  • Cú pháp đẹp cho vectơ [1 2 3], bản đồ {:bob 10, :jane 15} và bộ #{"a" "b" "c"} - Tôi xem xét những công cụ khá cần thiết cho lập trình hiện đại (ngoài danh sách tất nhiên!)

  • Cá nhân tôi thích sử dụng dấu ngoặc vuông cho các hình thức ràng buộc: ví dụ: (defn foo [a b] (+ a b)) - Tôi nghĩ rằng nó làm cho mã một chút rõ ràng hơn để đọc.

  • Nhấn mạnh vào lập trình lười biếng, chức năng với cấu trúc dữ liệu bền vững, không thay đổi - đặc biệt là tất cả thư viện Clojure cốt lõi được thiết kế để hỗ trợ điều này theo mặc định

  • Triển khai STM tuyệt vời cho đồng thời đa lõi. Tôi tin rằng Clojure có câu chuyện đồng thời tốt nhất của bất kỳ ngôn ngữ nào tại thời điểm này (xem này video để tự mình xây dựng thêm cho Rich Hickey)

  • Đó là một Lisp-1 (giống như Scheme), mà cá nhân tôi thích (tôi nghĩ bằng một ngôn ngữ chức năng nó có ý nghĩa để giữ cho các hàm và dữ liệu trong cùng một không gian tên)


44



1 cho STM. Đó là, bởi itselft, đủ để biện minh bằng cách sử dụng Clojure. - André Caron
Bạn vẫn có thể nhận STM bằng thư viện CL-STM. - Mike Manilone
@ AndréCaron chỉ khi bạn cần. - rightfold
Nếu bạn muốn viết một ứng dụng web đơn giản và lưu trữ trên máy chủ giá rẻ 5 đô la / tháng, điều đó rõ ràng là không thể thực hiện được với Clojure do JVM, đúng không? - Hexatonic
@ Hexatonic Tôi không có nhiều kinh nghiệm nhưng thật khó để tin rằng một máy tính sử dụng những ngày này sẽ không có JVM. - MasterMastic


Một sự khác biệt quan trọng giữa Clojure và Common Lisp là Clojure có tính mô tả chi tiết hơn về lập trình hàm. Triết lý của Clojure, thành ngữ, và một số ngôn ngữ / thư viện mức độ khuyến khích mạnh mẽ và đôi khi nhấn mạnh rằng bạn lập trình một cách chức năng (không có tác dụng phụ, không có trạng thái có thể thay đổi).

Lisp thường chắc chắn hỗ trợ lập trình chức năng, nhưng nó cũng cho phép lập trình trạng thái có thể thay đổi và bắt buộc.

Tất nhiên, có một số lợi ích cho lập trình hàm, trong lĩnh vực đồng thời và ngược lại. Nhưng tất cả đều bình đẳng, bạn cũng nên chọn lựa cách tiếp cận nào bạn muốn sử dụng cho từng tình huống. Clojure không hoàn toàn cấm lập trình bắt buộc, nhưng nó ít có sức chứa của phong cách đó hơn Common Lisp.


23



@Charlie Flowers: Tôi tin rằng trong Common Lisp có thể lập trình theo kiểu "thuần túy chức năng" (hỗ trợ cấu trúc dữ liệu liên tục, vv), nhưng đòi hỏi kỷ luật. Chính xác? - Ralph
Chỉ cần làm rõ "không có tác dụng phụ, không có trạng thái có thể thay đổi" - Clojure có trạng thái có thể thay đổi (refs, nguyên tử, tác nhân vv đều có thể thay đổi) nhưng yêu cầu bạn truy cập nó theo cách được kiểm soát (tức là thông qua cơ chế STM và giao dịch liên quan) cập nhật ngữ nghĩa) - mikera
@mikera: ngoại trừ Clojure dựa vào việc sử dụng các thư viện Java để có thể sử dụng được, và tất cả các thư viện đó yêu cầu kiểu dáng bắt buộc và có đầy đủ các tác dụng phụ. Tôi đã tìm thấy các ràng buộc với Java là một món quà độc ... - André Caron
@Andre - chắc chắn, nếu bạn quyết định sử dụng một thư viện yêu cầu trạng thái có thể thay đổi và ngữ nghĩa bắt buộc thì bạn phải quản lý điều này. Điều này không khác gì nếu bạn truy cập thư viện đó từ bất kỳ ngôn ngữ nào khác. Nhưng bạn có hai lựa chọn phong nha: a) Không sử dụng các thư viện như vậy - bạn có thể viết mã hoàn toàn tốt trong Clojure tinh khiết hoặc b) bọc sự phức tạp của giao tiếp với các thư viện này trong giao diện chức năng kiểu Clojure đẹp, thường dễ dàng macro hoặc đại lý vv Nhìn chung, tôi đã tìm thấy khả năng khai thác các thư viện Java một lợi ích lớn hơn nhiều so với vấn đề. - mikera
@ mikera: các thư viện có lợi ích. Tôi chỉ chỉ ra rằng việc sử dụng các thư viện Java (đây là một trong những mục tiêu chính của Rich Hickey cho ngôn ngữ) thực sự đi ngược lại khía cạnh "nhiều chức năng hơn so với các lisps" của Clojure. Ý kiến ​​của tôi có ý nghĩa: "trừ khi bạn viết lại / bọc các thư viện này, bạn sẽ nhận được mã bắt buộc và không được hưởng lợi từ các phần đẹp hơn của Clojure". - André Caron


Hãy nhớ rằng Clojure là một ngôn ngữ và thực hiện (thường là trên JVM). Lisp phổ biến là một ngôn ngữ với hơn mười triển khai khác nhau. Vì vậy, chúng tôi có một danh mục không phù hợp ngay tại đây. Ví dụ, bạn có thể so sánh Clojure với SBCL.

Nói chung là:

  • một phiên bản Common Lisp chạy trên JVM: ABCL

  • hầu hết các triển khai Common Lisp khác không

  • hầu hết các triển khai CL có khả năng đa nhiệm, một thư viện cung cấp một giao diện chung

  • Lisp thường có cú pháp cho mảng. Cú pháp cho các kiểu dữ liệu khác có thể được viết bởi người dùng và được cung cấp bởi các thư viện khác nhau.

  • Lisp thường hỗ trợ tối ưu hóa cuộc gọi đuôi cũng như không tiếp tục. Các triển khai cung cấp TCO và các thư viện cung cấp một số dạng tiếp tục.


19





Đây là một video hay với so sánh của Đề án (Racket chủ yếu) và Clojure.

Để công bằng, Racket có đường cú pháp (công cụ đọc bổ sung) cho các loại dữ liệu quá (#hash, #, dấu ngoặc vuông, v.v.)

Thêm vào đó, cách duy nhất của Clojure để thực hiện cuộc gọi đuôi thích hợp là sử dụng recur, đó là nhược điểm của việc biên dịch sang JVM.

Lưu ý rằng recur là cấu trúc vòng lặp không tốn nhiều chi phí duy nhất trong Clojure. Không có cuộc gọi đuôi   tối ưu hóa và sử dụng các cuộc gọi tự cho vòng lặp của giới hạn không xác định được khuyến khích. recur Là   chức năng và việc sử dụng nó ở vị trí đuôi được xác minh bởi trình biên dịch. (Biểu mẫu đặc biệt).


10



Liên kết là chết tôi đoán. - nawfal
@nawfal Tôi nghĩ tôi đã sửa nó - Daniil
Liên kết đã chết (một lần nữa?) - Throwaway Account 3 Million
Có vẻ như video trên liên kết đó có thể tìm thấy ở đây: vimeo.com/22675078. - GDP2
Cũng có trampoline cho các cuộc gọi đuôi. - HappyFace