Clojure vs inne Lisps [zamknięte]

93

Celem mojego pytania nie jest rozpoczęcie wojny o płomienie, ale raczej określenie, w jakich okolicznościach każdy język jest „najlepszym narzędziem do pracy”.

Przeczytałem kilka książek o Clojure ( Programming Clojure , Practical Clojure , The Joy of Clojure i Manning Early Access Edition of Clojure in Action ) i myślę, że to fantastyczny język. Obecnie czytam Let Over Lambda, który zajmuje się głównie makrami Common Lisp i jest również bardzo interesującym językiem.

Ja nie Lisp ekspert (więcej początkujących), ale to rodzina języków fascynuje mnie, podobnie jak programowanie funkcyjne, w ogóle.

Zalety Clojure (i wady „innych”):

  • Działa na JVM.

    • JVM to bardzo stabilne, wydajne środowisko językowe, które całkiem dobrze spełnia marzenie Sun'a o „Napisz raz, uruchom [prawie] wszędzie”. Mogę pisać kod na moim Macbooku Pro, skompilować go do wykonywalnego pliku JAR, a następnie uruchomić go w systemie Linux i Microsoft Windows z niewielkimi dodatkowymi testami.

    • JVM (Hotspot i inne) obsługuje wysokiej jakości wyrzucanie elementów bezużytecznych oraz bardzo wydajną kompilację i optymalizację w trybie just-in-time. Tam, gdzie jeszcze kilka lat temu pisałem wszystko, co musiało działać szybko w C, teraz nie waham się robić tego w Javie.

    • Model standardowy, prosty, wielowątkowy. Czy Common Lisp ma standardowy pakiet wielowątkowy?

    • Zrywa monotonię wszystkich tych nawiasów za pomocą [], {}i #{}chociaż eksperci Common Lisp prawdopodobnie powiedzą mi, że za pomocą makr czytnika można je dodać do CL.

Wady Clojure :

  • Działa na JVM.
    • Bez rekurencji ogona lub kontynuacji. Czy Common Lisp obsługuje kontynuacje? Uważam, że program wymaga wsparcia dla obu.

Zalety innych (w szczególności Common Lisp) (i wady Clojure):

  • Definiowane przez użytkownika makra czytnika.

  • Inne zalety?

Myśli? Inne różnice?

Ralph
źródło
15
osobiście lubię jeden rodzaj nawiasów;) wygląda jak „czystszy” kod
Moe
3
Z tego, co przeczytałem na twojej liście zalet, myślę, że może polubisz również Erlang www.erlang.org
Peer Stritzinger
4
Clojure obsługuje jawną rekurencję ogonów za pośrednictwem specjalnego formularza „recur”. Umożliwia to uzyskanie wszystkich korzyści z rekurencji ogonowej, pod warunkiem, że wyraźnie o nią poprosisz (jedynym wyjątkiem jest to, że obecnie nie obsługuje ona rekurencji wzajemnych ogonów między wieloma funkcjami).
mikera
1
Clojure wspiera również kontynuacje, przynajmniej w sensie „stylu przechodzenia kontynuacji”. Masz rację, że nie ma on kontynuacji pierwszej klasy. patrz stackoverflow.com/questions/1173133/continuations-in-clojure
mikera
@mikera: rekurencja ogonowa w jednej funkcji. Dwie funkcje wywołujące się nawzajem trzeba wykonać za pomocą "trampoliny", która jest trochę niezdarna (ale na swój sposób elegancka :-)).
Ralph

Odpowiedzi:

52

Moja osobista lista powodów, dla których wolę Clojure od innych Lispsów (ps, nadal uważam, że wszystkie Lispy są świetne!):

  • Działa na JVM - w ten sposób uzyskuje automatyczny dostęp do fantastycznej inżynierii w samej JVM (zaawansowane algorytmy zbierania śmieci, optymalizacja HotSpot JIT itp.)

  • Bardzo dobra interoperacyjność Java - zapewnia kompatybilność z szeroką gamą bibliotek w ekosystemie języków Java / JVM. Użyłem Clojure jako języka „klejącego” do łączenia różnych bibliotek Java z dobrym skutkiem. Ponieważ opracowuję również dużo kodu Java, pomocne jest dla mnie to, że Clojure dobrze integruje się z narzędziami Java (np. Używam Maven, Eclipse z wtyczką Counterclockwise do mojego rozwoju Clojure)

  • Niezła składnia wektorów [1 2 3], map {:bob 10, :jane 15}i zestawów #{"a" "b" "c"}- uważam te dość niezbędne narzędzia do współczesnego programowania (oprócz list oczywiście!)

  • Osobiście podoba mi się używanie nawiasów kwadratowych do oprawiania formularzy: np. (defn foo [a b] (+ a b))- Myślę, że dzięki temu kod jest nieco bardziej czytelny.

  • Nacisk na leniwe, funkcjonalne programowanie z trwałymi, niezmiennymi strukturami danych - w szczególności cała podstawowa biblioteka Clojure została zaprojektowana do obsługi tego domyślnie

  • Doskonała implementacja STM dla współbieżności wielordzeniowej. Uważam, że Clojure ma obecnie najlepszą historię współbieżności ze wszystkich języków (zobacz ten film, aby uzyskać więcej informacji od samego Richa Hickeya )

  • To Lisp-1 (jak Scheme), który osobiście wolę (myślę, że w języku funkcjonalnym sensowne jest utrzymywanie funkcji i danych w tej samej przestrzeni nazw)

mikera
źródło
2
+1 dla STM. Samo to wystarczy, aby uzasadnić używanie Clojure.
André Caron
2
Nadal można uzyskać STM za pomocą biblioteki CL-STM.
Mike Manilone
2
@ AndréCaron tylko wtedy, gdy tego potrzebujesz.
prawy
Jeśli chciałeś napisać prostą aplikację internetową i hostować ją na, powiedzmy, tanim hoście za 5 USD miesięcznie, to oczywiście nie jest możliwe w przypadku Clojure ze względu na JVM, prawda?
Hexatonic
@Hexatonic Nie mam dużego doświadczenia, ale trudno uwierzyć, że obecnie używana maszyna nie miałaby JVM.
MasterMastic
25

Należy pamiętać, że Clojure to język i implementacja (zwykle w JVM). Common Lisp to język z ponad dziesięcioma różnymi implementacjami. Mamy więc tutaj niedopasowanie kategorii. Możesz na przykład porównać Clojure z SBCL.

Ogólnie:

  • wersja Common Lisp działa na JVM: ABCL

  • większość innych implementacji Common Lisp nie

  • większość implementacji CL ma możliwości wielozadaniowości, biblioteka zapewnia wspólny interfejs

  • Common Lisp ma składnię dla tablic. Składnia dla innych typów danych może być napisana przez użytkownika i są one dostarczane przez różne biblioteki.

  • Common Lisp nie obsługuje ani optymalizacji wywołań końcowych, ani kontynuacji. Wdrożenia zapewniają całkowity koszt posiadania, a biblioteki zapewniają pewną formę kontynuacji.

Rainer Joswig
źródło
24

Ważną różnicą między Clojure a Common Lisp jest to, że Clojure jest bardziej nakazowy w zakresie programowania funkcjonalnego. Filozofia Clojure, idiomy i do pewnego stopnia język / biblioteki silnie zachęcają, a czasami nalegają, aby programować w funkcjonalny sposób (bez skutków ubocznych, bez zmiennego stanu).

Common Lisp zdecydowanie obsługuje programowanie funkcjonalne, ale umożliwia również programowanie w trybie mutowalnym i imperatywnym.

Oczywiście programowanie funkcjonalne ma wiele zalet, jeśli chodzi o współbieżność i nie tylko. Ale skoro wszystko inne jest równe, dobrze jest mieć wybór, które podejście chcesz zastosować w każdej sytuacji. Clojure nie zabrania całkowicie programowania imperatywnego, ale jest mniej dostosowany do tego stylu niż Common Lisp.

Charlie Flowers
źródło
3
@Charlie Flowers: Uważam, że w Common Lisp można programować w stylu „czysto funkcjonalnym” (trwałe wsparcie struktury danych itp.), Ale wymaga to dyscypliny. Poprawny?
Ralph
2
Tylko wyjaśnienie dotyczące „bez skutków ubocznych, bez stanu mutowalnego” - Clojure ma zmienny stan (odniesienia, atomy, agenty itp. Są zmienne), ale wymaga dostępu do niego w kontrolowany sposób (tj. Poprzez mechanizmy STM i powiązane transakcje aktualizacja semantyki)
mikera
5
@mikera: poza tym, że Clojure polega na używaniu bibliotek Java, aby były użyteczne, a wszystkie te biblioteki wymagają imperatywnego stylu i są pełne efektów ubocznych. Uważam, że powiązania z Javą to zatruty prezent ...
André Caron
1
@Andre - oczywiście, jeśli zdecydujesz się użyć biblioteki, która wymaga mutowalnego stanu i imperatywnej semantyki, musisz tym zarządzać. Nie różni się to od sytuacji, gdy uzyskałeś dostęp do takiej biblioteki z dowolnego innego języka. Ale masz dwie przyzwoite opcje: a) Nie używaj takich bibliotek - możesz napisać doskonale dobry kod w czystym Clojure lub b) zawinąć złożoność interakcji z tymi bibliotekami w ładnym funkcjonalnym interfejsie w stylu Clojure, który zwykle jest łatwy dzięki makra lub agenty itp. Ogólnie stwierdziłem, że umiejętność okiełznania bibliotek Javy przynosi dużo większą korzyść niż jest to problem.
mikera
4
@mikera: biblioteki przynoszą korzyści. Zwracam tylko uwagę, że używanie bibliotek Java (jest to jeden z głównych celów Richa Hickeya dla języka) naprawdę jest sprzeczne z „bardziej funkcjonalnym niż inne seplony” aspektem Clojure. Mój komentarz miał oznaczać: „jeśli nie przepiszesz / nie zapakujesz tych bibliotek, otrzymasz kod wyglądający imperatywnie i nie skorzystasz z ładniejszych części Clojure”.
André Caron
10

Oto dobry film z porównaniem Scheme (głównie Racket) i Clojure .

Aby być uczciwym, Racket ma cukier składniowy (dodatkowe elementy czytnika) również dla typów danych (#hash, #, nawiasy kwadratowe itp.)

Dodatkowo, jedynym sposobem Clojure na wykonanie prawidłowego wywołania końcowego jest użycie recur, to jest wada kompilacji do JVM.

Zauważ, że recurjest to jedyna niezużywająca stosu konstrukcja pętli w Clojure. Nie ma optymalizacji wywołań ogonowych i odradza się używanie wywołań własnych do zapętlania nieznanych granic. recurjest funkcjonalny i jego użycie w pozycji końcowej jest weryfikowane przez kompilator. ( Formularze specjalne ).

Daniil
źródło
Myślę, że Link nie żyje.
nawfal
1
@nawfal Myślę, że to naprawiłem
Daniil
6
Link nie żyje (znowu?)
Wyrzuć konto
1
Wygląda na to, że film pod tym linkiem można znaleźć tutaj: vimeo.com/22675078 .
GDP2
Jest też trampolinewywołanie ogonowe.
HappyFace