Clojure so với các Lisps khác [đã đóng]


93

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

Tôi đã đọc một số cuốn sách về Clojure (Clojure lập trình , Clojure thực tế , Niềm vui của Clojure và ấn bản Manning Early Access của Clojure in Action ), và tôi nghĩ đó là một ngôn ngữ tuyệt vời. Tôi hiện đang đọc Let Over Lambda , phần lớn liên quan đến các macro Lisp chung, và nó cũng là một ngôn ngữ rất thú vị.

Tôi không phải là một chuyên gia về Lisp (nhiều người mới học), nhưng họ ngôn ngữ này làm tôi mê mẩn, cũng như lập trình hàm 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ữ rất ổn định, hiệu suất cao, đáp ứng khá tốt ước mơ "Viết một lần, chạy [hầu như] ở bất cứ đâu" của Sun. Tôi có thể viết mã trên Macbook Pro của mình, biên dịch nó thành tệp JAR có thể thực thi và sau đó chạy nó trên Linux và Microsoft Windows với một ít thử nghiệm bổ sung.

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

    • Mô hình tiêu chuẩn, đơn giản, đa luồng. Common Lisp có gói đa luồng tiêu chuẩn không?

    • Breaks lên sự đơn điệu của tất cả những dấu ngoặc đơn với [], {}#{}, mặc dù các chuyên gia Common Lisp có thể sẽ nói với tôi rằng với các macro đọc, bạn có thể thêm những để CL.

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

  • Chạy trên JVM.
    • Không có đệ quy đuôi hoặc liên tục. Common Lisp có hỗ trợ liên tục không? Tôi tin rằng chương trình yêu cầu hỗ trợ cho cả hai.

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

  • Macro trình đọc do người dùng xác định.

  • Những lợi thế khác?

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


15
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

3
Từ những gì tôi đọc trên Ưu điểm của bạn liệt kê tôi tìm có lẽ bạn có lẽ cũng giống như Erlang www.erlang.org
Peer Stritzinger

4
Clojure không hỗ trợ đệ quy đuôi rõ ràng thông qua biểu mẫu đặc biệt "định kỳ". Điều này cho phép bạn nhận được tất cả các lợi ích của đệ quy đuôi miễn là bạn yêu cầu rõ ràng (ngoại lệ duy nhất là nó hiện không hỗ trợ đệ quy đuôi lẫn nhau giữa nhiều hàm).
mikera

1
Clojure cũng hỗ trợ sự liên tục, ít nhất là theo nghĩa "phong cách tiếp tục đi qua". Bạn đúng rằng nó không có các lớp liên tục đầu tiên. xem stackoverflow.com/questions/1173133/continuation-in-clojure
mikera

@mikera: Đệ quy đuôi trên một hàm. Hai hàm gọi lẫn nhau phải được thực hiện bằng "trampolining", kiểu này khá kludgy (nhưng tao nhã theo cách riêng của nó :-)).
Ralph

Câu trả lời:


52

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

  • Chạy trên JVM - do đó có quyền truy cập tự động vào kỹ thuật tuyệt vời trong chính JVM (thuật toán thu gom rác nâng cao, 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 hàng loạt 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 nhiều mã Java nên rất hữu ích cho tôi rằng 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 Counterclockwise để 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à tập hợp #{"a" "b" "c"}- tôi coi đây là những công cụ khá cần thiết cho lập trình hiện đại (tất nhiên là ngoài danh sách!)

  • Cá nhân tôi thích việc sử dụng dấu ngoặc vuông cho các biểu mẫu ràng buộc: ví dụ (defn foo [a b] (+ a b))- Tôi nghĩ rằng nó làm cho mã rõ ràng hơn một chút để đọ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, bất biến - đặ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 hay nhất của bất kỳ ngôn ngữ nào vào lúc này (xem video này để biết thêm chi tiết của chính Rich Hickey )

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


2
+1 cho STM. Nói cách khác, nó đủ để biện minh cho việc sử dụng Clojure.
André Caron

2
Bạn vẫn có thể nhận STM bằng cách sử dụng thư viện CL-STM.
Mike Manilone

2
@ AndréCaron chỉ khi bạn cần.
đúng

Nếu bạn muốn viết một ứng dụng web đơn giản và lưu trữ nó, chẳng hạn như một máy chủ lưu trữ giá rẻ $ 5 / tháng, điều đó rõ ràng là không thể 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 một chiếc máy đang được sử dụng ngày nay lại không có JVM.
MasterMastic

25

Hãy nhớ rằng Clojure là một ngôn ngữ và một cách triển khai (thường là trên JVM). Lisp chung là một ngôn ngữ có hơn mười cách triển khai khác nhau. Vì vậy, chúng tôi có một danh mục không khớ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 của Common Lisp chạy trên JVM: ABCL

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

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

  • Lisp chung 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.

  • Common Lisp không hỗ trợ tối ưu hóa cuộc gọi đuôi hay tính liên tục. Việc triển khai cung cấp TCO và các thư viện cung cấp một số hình thức liên tục.


24

Một điểm khác biệt quan trọng giữa Clojure và Common Lisp là Clojure thiên về lập trình chức năng. Triết lý, thành ngữ của Clojure và ở một mức độ nào đó ngôn ngữ / thư viện khuyến khích mạnh mẽ và đôi khi nhấn mạnh rằng bạn lập trình theo 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).

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

Tất nhiên, có một số lợi ích đối với lập trình hàm, trong lĩnh vực đồng thời và các mặt khác. Nhưng tất cả đều bình đẳng, cũng rất tốt nếu bạn được lựa chọn cách tiếp cận mà 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 mệnh lệnh, nhưng nó ít phù hợp với phong cách đó hơn so với Common Lisp.


3
@Charlie Flowers: Tôi tin rằng trong Common Lisp, có thể lập trình theo phong cách "thuần chức năng" (hỗ trợ cấu trúc dữ liệu liên tục, v.v.), nhưng cần có kỷ luật. Chính xác?
Ralph

2
Chỉ cần giải thích rõ về "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, v.v. đề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

5
@mikera: ngoại trừ việc 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 đó đều yêu cầu kiểu mệnh lệnh và đầy tác dụng phụ. Tôi nhận thấy các ràng buộc với Java là một món quà độc hại ...
André Caron

1
@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 một thư viện như vậy từ bất kỳ ngôn ngữ nào khác. Nhưng bạn có hai lựa chọn phù hợp: 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 bằng Clojure thuần túy hoặc b) gói gọn sự phức tạp của việc giao tiếp với các thư viện này trong một giao diện chức năng kiểu Clojure đẹp mắt, điều này thường dễ dàng với macro hoặc tác nhân, v.v. Nhìn chung, tôi thấy khả năng khai thác các thư viện Java mang lại lợi ích lớn hơn nhiều so với vấn đề.
mikera

4
@mikera: các thư viện có một 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 đối với ngôn ngữ này) thực sự đi ngược lại khía cạnh "nhiều chức năng hơn các ngôn ngữ lisp khác" của Clojure. Nhận xét của tôi có ý nghĩa: "trừ khi bạn viết lại / gói các thư viện này, bạn sẽ nhận được mã bắt buộc và sẽ không được hưởng lợi từ các phần đẹp hơn của Clojure".
André Caron

10

Đây là một video hay với sự so sánh giữa Scheme (chủ yếu là Vợt) và Clojure .

Công bằng mà nói, Racket cũng có đường cú pháp (công cụ đọc bổ sung) cho các loại dữ liệu (#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 một 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 đó recurlà cấu trúc lặp duy nhất không tiêu tốn ngăn xếp trong Clojure. Không có tối ưu hóa cuộc gọi đuôi và không khuyến khích sử dụng các lệnh tự gọi để lặp lại các giới hạn không xác định. recurlà chức năng và việc sử dụng nó ở vị trí đuôi được trình biên dịch xác nhận. ( Hình thức đặc biệt ).


Tôi đoán là liên kết đã chết.
nawfal

1
@nawfal Tôi nghĩ rằng tôi cố định nó
Daniil

6
Liên kết đã chết (một lần nữa?)
Tài khoản Quăng đi

1
Có vẻ như bạn có thể tìm thấy video trên liên kết đó tại đây: vimeo.com/22675078 .
GDP

Cũng có trampolinecho các cuộc gọi đuôi.
HappyFace
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.